toeverything/AFFiNE · error · BlobQuotaExceeded

blob_quota_exceeded

blob_quota_exceeded

Error message

You have exceeded your blob size quota.

What it means

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.

Source

Thrown at packages/backend/server/src/core/workspaces/resolvers/blob.ts:188

  @Mutation(() => String)
  async setBlob(
    @CurrentUser() user: CurrentUser,
    @Args('workspaceId') workspaceId: string,
    @Args({ name: 'blob', type: () => GraphQLUpload })
    blob: FileUpload
  ) {
    await this.ac
      .user(user.id)
      .workspace(workspaceId)
      .assert('Workspace.Blobs.Write');

    const checkExceeded =
      await this.quota.getWorkspaceQuotaCalculator(workspaceId);

    let result = checkExceeded(0);
    if (result?.blobQuotaExceeded) {
      throw new BlobQuotaExceeded();
    } else if (result?.storageQuotaExceeded) {
      throw new StorageQuotaExceeded();
    }

    const buffer = await readBuffer(blob.createReadStream(), checkExceeded);

    await this.storage.put(workspaceId, blob.filename, buffer);
    return blob.filename;
  }

  @Mutation(() => BlobUploadInit)
  async createBlobUpload(
    @CurrentUser() user: CurrentUser,
    @Args('workspaceId') workspaceId: string,
    @Args('key') key: string,
    @Args('size', { type: () => Int }) size: number,
    @Args('mime') mime: string
  ): Promise<BlobUploadInit> {

View on GitHub (pinned to 26c515e050)

Solutions

  1. Free up blob storage (delete unused blobs) to get back under quota.
  2. Upgrade the workspace plan to raise the blob quota.
  3. Confirm the quota calculator/usage metrics are fresh.
  4. Pre-check quota in the UI before letting the user pick a file.

Example fix

// before
await storage.put(ws, file.name, await readBuffer(file.createReadStream()))
// after
const calc = await quota.getWorkspaceQuotaCalculator(ws)
if (calc(0)?.blobQuotaExceeded) return showQuotaUpgrade()
await storage.put(ws, file.name, await readBuffer(file.createReadStream(), calc))
Defensive patterns

Strategy: validation

Validate before calling

const calc = await quota.getWorkspaceQuotaCalculator(workspaceId)
if (calc(0)?.blobQuotaExceeded) return promptUpgradeOrCleanup()

Try / catch

try { await uploadBlob(file) } catch (e) {
  if (e.code === 'blob_quota_exceeded') promptUpgradeOrCleanup()
  else throw e
}

Prevention

When it happens

Trigger: 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).

Common situations: Plan downgrade reduced the quota below current usage; large accumulated blobs; quota calculator stale metrics; shared workspace hitting free-tier limits.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/095f0cd1e6b72539. Report an issue: GitHub.