# Instruction Limit Exceeded During File Upload in Canister

**URL:** <https://forum.dfinity.org/t/instruction-limit-exceeded-during-file-upload-in-canister/38758>\
**Category:** Developers\
**Tags:** Discussing\
**Created:** [December 11, 2024, 10:50pm UTC](https://forum.dfinity.org/t/instruction-limit-exceeded-during-file-upload-in-canister/38758 "2024-12-11T22:50:16Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![byurhannurula](https://avatars.discourse-cdn.com/v4/letter/b/958977/32.png) [@byurhannurula](https://forum.dfinity.org/u/byurhannurula)\
**Post date:** [December 11, 2024, 10:50pm UTC](https://forum.dfinity.org/t/instruction-limit-exceeded-during-file-upload-in-canister/38758/1 "2024-12-11T22:50:16Z")

</div>

Hello everyone,

I’m currently working on a **file storage caniste** where files are uploaded in chunks and stored using **stable memory** (`StableBTreeMap`).

## **Problem:**

When trying to upload a file (chunked or otherwise), I receive the error:

```auto
Canister exceeded the limit of 40000000000 instructions for single message execution.

```

I have tried different methods but it’s always same at the end asked to AI for help and generated something more complex but with this code throws error even on `initializeUpload` method.

## Code:

```ts
export default class StorageCanister {
  private fileStorage = StableBTreeMap<string, File>(0); // Metadata storage
  private chunkStorage = StableBTreeMap<string, Uint8Array>(1); // Chunk storage
  private serviceStorage = StableBTreeMap<Principal, Service>(2); // Service management

  private uploadStates = new Map<string, UploadState>(); // Tracks upload states per file

  @update([IDL.Text, IDL.Text, IDL.Nat], IDL.Bool)
  async initializeUpload(
    fileId: string,
    fileName: string,
    totalSize: bigint,
  ): Promise<boolean> {
    try {
      if (!this.serviceStorage.containsKey(caller())) {
        throw { Unauthorized: "Unauthorized access!" };
      }

      // Uncomment this if you want to check for free space
      // if (!(await this.checkCanisterFreeSpace(totalSize))) {
      // throw { UploadError: "No sufficient space in the canister!" };
      // }

      const newFile: File = {
        id: fileId,
        name: fileName,
        size: totalSize,
        userId: caller().toText(),
        createdAt: time(),
        chunkCount: 0,
      };

      this.fileStorage.insert(fileId, newFile);
      this.uploadStates.set(fileId, { NotStarted: null });

      return true;
    } catch (error) {
      return false;
    }
  }

  @update([IDL.Text, IDL.Nat, IDL.Vec(IDL.Nat8)], IDL.Bool)
  async uploadChunk(
    fileId: string,
    chunkId: ChunkId,
    chunkData: Uint8Array,
  ): Promise<boolean> {
    try {
      if (!this.serviceStorage.containsKey(caller())) {
        throw { Unauthorized: "Unauthorized access!" };
      }

      const currentState = this.uploadStates.get(fileId);
      if (!currentState) {
        throw { UploadError: "Upload not initialized" };
      }

      if ("Completed" in currentState) {
        throw { UploadError: "Upload already completed" };
      }

      if (
        "InProgress" in currentState &&
        currentState.InProgress.chunkId + 1n !== chunkId
      ) {
        throw { UploadError: "Invalid chunk order" };
      }

      const chunkKey = `${fileId}-${chunkId}`;
      this.chunkStorage.insert(chunkKey, chunkData);

      const file = this.fileStorage.get(fileId);
      if (!file) {
        throw { UploadError: "File not found" };
      }

      const updatedFile = {
        ...file,
        chunkCount: file.chunkCount + 1,
      };

      this.fileStorage.insert(fileId, updatedFile);

      this.uploadStates.set(fileId, { InProgress: { chunkId } });

      return true;
    } catch (error) {
      return false;
    }
  }

  @update([IDL.Text], FileResult)
  async finalizeUpload(fileId: string): Promise<FileResult> {
    try {
      if (!this.serviceStorage.containsKey(caller())) {
        throw { Unauthorized: "Unauthorized access!" };
      }

      const currentState = this.uploadStates.get(fileId);

      if (!currentState) {
        throw { NotKnown: "Upload not initialized" };
      }

      if ("NotStarted" in currentState) {
        throw { NotKnown: "Upload not started" };
      }

      if ("Completed" in currentState) {
        throw { NotKnown: "Upload already completed" };
      }

      this.uploadStates.set(fileId, { Completed: null });

      const file = this.fileStorage.get(fileId);
      if (!file) {
        throw { NotFound: "File not found" };
      }

      return {
        Ok: {
          id: file.id,
          name: file.name,
          canisterId: id().toText(),
        },
      };
    } catch (error) {
      return { Err: handleError(error) };
    }
  }

  // Retrieve a specific file chunk
  @query([IDL.Text], FileChunkResult)
  getFile(fileId: string, chunkNumber: bigint): FileChunkResult {
    try {
      if (!this.serviceStorage.containsKey(caller())) {
        throw { Unauthorized: "Unauthorized access!" };
      }

      const file = this.fileStorage.get(fileId);
      if (!file) {
        throw { NotFound: `File with ID ${fileId} not found.` };
      }

      const chunkKey = `${fileId}-${chunkNumber}`;
      const chunk = this.chunkStorage.get(chunkKey);
      if (!chunk) {
        throw {
          NotFound: `Chunk ${chunkNumber} not found for file ${fileId}.`,
        };
      }

      const hasNext = chunkNumber + 1n < file.chunkCount;

      return {
        Ok: {
          id: file.id,
          name: file.name,
          chunk,
          hasNext,
        },
      };
    } catch (error) {
      return { Err: handleError(error) };
    }
  }

  private async checkCanisterFreeSpace(fileSize: bigint): Promise<boolean> {
    try {
      const status = await await call("aaaaa-aa", "canister_status", {
        paramIdlTypes: [CanisterStatusArgs],
        returnIdlType: CanisterStatusResult,
        args: [{ canister_id: id() }],
      });

      if (!status || !status.memory_size) {
        throw new Error("Unable to retrieve canister status or memory size.");
      }

      const storageLimit = BigInt(500 * 1024 * 1024 * 1024); // Set limit to 500 GiB
      const threshold = (storageLimit * BigInt(90)) / BigInt(100); // Use only up to 90% of storage

      const usedStorage = BigInt(status.memory_size.toString());

      // Check if there is enough space for the file
      return threshold - usedStorage >= fileSize;
    } catch (error) {
      return false; // Default to false in case of an error
    }
  }
}

```

## Dependencies:

```auto
"@dfinity/agent": "^2.1.3",
"@dfinity/candid": "^2.1.3",
"azle": "^0.24.1",

```

Any guidance or recommendations would be greatly appreciated! Thank you in advance!

---

<div class="post-metadata">

**Author:** ![lastmjs](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/lastmjs/32/3406_2.png) [@lastmjs](https://forum.dfinity.org/u/lastmjs)\
**Post date:** [December 14, 2024, 9:24pm UTC](https://forum.dfinity.org/t/instruction-limit-exceeded-during-file-upload-in-canister/38758/2 "2024-12-14T21:24:42Z")

</div>

We’re discussing this in the Discord correct?
