{"record":{"id":"489edf09b77d1043","repo":"toeverything/AFFiNE","slug":"blob-quota-exceeded-489edf","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/plugins/copilot/workspace/resolver.ts","lineNumber":180,"sourceCode":"  ): Promise<CopilotWorkspaceArtifactType> {\n    await this.ac\n      .user(user.id)\n      .workspace(workspaceId)\n      .assert('Workspace.Settings.Update');\n\n    if (!this.copilotWorkspace.canEmbedding) {\n      throw new CopilotEmbeddingUnavailable();\n    }\n\n    const lockFlag = `${COPILOT_LOCKER}:workspace:${workspaceId}`;\n    await using lock = await this.mutex.acquire(lockFlag);\n    if (!lock) {\n      throw new TooManyRequest('Server is busy');\n    }\n\n    const length = Number(ctx.req.headers['content-length']);\n    if (length && length >= MAX_EMBEDDABLE_SIZE) {\n      throw new BlobQuotaExceeded();\n    }\n\n    try {\n      return await this.copilotWorkspace.addArtifact(workspaceId, content);\n    } catch (e) {\n      // passthrough user friendly error\n      if (e instanceof UserFriendlyError) {\n        throw e;\n      }\n      throw new CopilotFailedToAddWorkspaceArtifact({\n        message: e instanceof Error ? e.message : String(e),\n      });\n    }\n  }\n\n  @Mutation(() => Boolean, {\n    name: 'removeWorkspaceArtifact',\n    complexity: 2,","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/copilot/workspace/resolver.ts#L162-L198","documentation":"The resolver reads the request's content-length header and throws BlobQuotaExceeded (code blob_quota_exceeded) when it is >= MAX_EMBEDDABLE_SIZE (50 MB, defined in packages/backend/server/src/plugins/copilot/utils.ts). This is the per-artifact embedding size cap for the copilot workspace.","triggerScenarios":"Uploading an artifact whose declared content-length is 50 MB or more: large PDFs, audio recordings, or dumps passed directly to addWorkspaceArtifact.","commonSituations":"Documents that exceed the cap because they embed images; proxies that strip the content-length header (this check is skipped, and oversized bodies then fail later during processing); callers assuming no size limit because GraphQL accepts any upload.","solutions":["Reduce the artifact below 50 MB or split it into meaningful parts (extract text, compress media)","Compress or transcode the file before upload","If you self-host and genuinely need bigger docs, raise MAX_EMBEDDABLE_SIZE and matching body-size limits in your deployment - but mind the embedding provider's token limits"],"exampleFix":"// before\nawait mutate({ workspaceId, blob: file }); // 80MB pdf -> error\n\n// after\nif (file.size >= 50 * 1024 * 1024) throw new Error('artifact too large');\nawait mutate({ workspaceId, blob: await shrink(file) });","handlingStrategy":"validation","validationCode":"const MAX_EMBEDDABLE_SIZE = 50 * 1024 * 1024;\nif (file.size >= MAX_EMBEDDABLE_SIZE) {\n  throw new RangeError(`artifact is ${file.size} bytes; cap is ${MAX_EMBEDDABLE_SIZE}`);\n}\nawait mutate({ workspaceId, blob: file });","typeGuard":"const isEmbeddableSize = (f: File): boolean =>\n  f.size < 50 * 1024 * 1024;","tryCatchPattern":"try {\n  await mutate({ workspaceId, blob: file });\n} catch (e) {\n  if (e?.code === 'blob_quota_exceeded') {\n    file = await compressOrSplit(file); // then retry once\n    return mutate({ workspaceId, blob: file });\n  }\n  throw e;\n}","preventionTips":["Check File.size against the 50 MB cap before opening the upload stream","Ensure your proxy forwards content-length - the server's check relies on it, and a missing header only defers the failure","Prefer extracting text or compressing media instead of uploading raw large documents"],"tags":["copilot","upload","size-limit","embedding","quota"],"backgroundTag":"payload-too-large","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}