{"record":{"id":"095f0cd1e6b72539","repo":"toeverything/AFFiNE","slug":"blob-quota-exceeded","errorCode":"blob_quota_exceeded","errorMessage":"You have exceeded your blob size quota.","messagePattern":"You have exceeded your blob size quota\\.","errorType":"exception","errorClass":"BlobQuotaExceeded","httpStatus":402,"severity":"error","filePath":"packages/backend/server/src/core/workspaces/resolvers/blob.ts","lineNumber":188,"sourceCode":"\n  @Mutation(() => String)\n  async setBlob(\n    @CurrentUser() user: CurrentUser,\n    @Args('workspaceId') workspaceId: string,\n    @Args({ name: 'blob', type: () => GraphQLUpload })\n    blob: FileUpload\n  ) {\n    await this.ac\n      .user(user.id)\n      .workspace(workspaceId)\n      .assert('Workspace.Blobs.Write');\n\n    const checkExceeded =\n      await this.quota.getWorkspaceQuotaCalculator(workspaceId);\n\n    let result = checkExceeded(0);\n    if (result?.blobQuotaExceeded) {\n      throw new BlobQuotaExceeded();\n    } else if (result?.storageQuotaExceeded) {\n      throw new StorageQuotaExceeded();\n    }\n\n    const buffer = await readBuffer(blob.createReadStream(), checkExceeded);\n\n    await this.storage.put(workspaceId, blob.filename, buffer);\n    return blob.filename;\n  }\n\n  @Mutation(() => BlobUploadInit)\n  async createBlobUpload(\n    @CurrentUser() user: CurrentUser,\n    @Args('workspaceId') workspaceId: string,\n    @Args('key') key: string,\n    @Args('size', { type: () => Int }) size: number,\n    @Args('mime') mime: string\n  ): Promise<BlobUploadInit> {","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/workspaces/resolvers/blob.ts#L170-L206","documentation":"Thrown before reading a blob upload stream when checkExceeded(0) already reports blobQuotaExceeded: the workspace is already over its blob-size quota before this upload even starts, so the request is rejected outright.","triggerScenarios":"The setBlob mutation is called when the workspace's blob-size usage is already above its plan's blob quota (the calculator is invoked at size 0).","commonSituations":"Plan downgrade reduced the quota below current usage; large accumulated blobs; quota calculator stale metrics; shared workspace hitting free-tier limits.","solutions":["Free up blob storage (delete unused blobs) to get back under quota.","Upgrade the workspace plan to raise the blob quota.","Confirm the quota calculator/usage metrics are fresh.","Pre-check quota in the UI before letting the user pick a file."],"exampleFix":"// before\nawait storage.put(ws, file.name, await readBuffer(file.createReadStream()))\n// after\nconst calc = await quota.getWorkspaceQuotaCalculator(ws)\nif (calc(0)?.blobQuotaExceeded) return showQuotaUpgrade()\nawait storage.put(ws, file.name, await readBuffer(file.createReadStream(), calc))","handlingStrategy":"validation","validationCode":"const calc = await quota.getWorkspaceQuotaCalculator(workspaceId)\nif (calc(0)?.blobQuotaExceeded) return promptUpgradeOrCleanup()","typeGuard":null,"tryCatchPattern":"try { await uploadBlob(file) } catch (e) {\n  if (e.code === 'blob_quota_exceeded') promptUpgradeOrCleanup()\n  else throw e\n}","preventionTips":["Show live quota usage in the upload UI.","Warn before the limit is hit.","Clean up orphan blobs periodically."],"tags":["quota","blobs","limits","billing"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}