toeverything/AFFiNE · error · StorageQuotaExceeded

storage_quota_exceeded

storage_quota_exceeded

Error message

You have exceeded your storage quota.

What it means

Thrown by BlobResolver.setBlob when checkExceeded(0) reports storageQuotaExceeded — the workspace's total storage usage is already at or over the plan's storage quota, so the upload is refused before reading the stream. Sibling of BlobQuotaExceeded in the same pre-check; this one is about aggregate bytes.

Solutions

  1. Free storage: delete large blobs / prune old data to drop usage below quota
  2. Upgrade the plan's storage quota
  3. Check current usage vs quota via the quota query before attempting uploads
  4. Audit for orphaned objects inflating counted usage
Defensive patterns

Strategy: validation

Validate before calling

const quota = await getWorkspaceQuota(wsId);
if (quota.storageUsage >= quota.storageQuota) {
  return showStorageQuotaExceededUI(quota);
}
await setBlob(wsId, file);

Type guard

function isStorageQuotaExceeded(e: unknown): e is { code: 'storage_quota_exceeded' } {
  return typeof e === 'object' && e !== null && (e as any).code === 'storage_quota_exceeded';
}

Try / catch

try {
  return await setBlob(wsId, file);
} catch (e) {
  if (isStorageQuotaExceeded(e)) {
    return offerFreeStorageOrUpgrade(); // hard stop — do not retry blindly
  }
  throw e;
}

Prevention

When it happens

Trigger: GraphQL setBlob on a workspace whose total storage (blobs + other counted usage) already exceeds the plan limit; the zero-byte probe failing means even a 1-byte upload would be rejected.

Common situations: Large media libraries on small plans; usage left over after a downgrade; storage accounting including pending uploads inflating the total.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/76c76f40d48728fa. Report an issue: GitHub.

Appendix: source

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

  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> {
    await this.ac
      .user(user.id)

View on GitHub (pinned to b4c8548c09)