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
- Free storage: delete large blobs / prune old data to drop usage below quota
- Upgrade the plan's storage quota
- Check current usage vs quota via the quota query before attempting uploads
- 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
- Show storage usage vs quota before large uploads
- Provide cleanup tooling for old/large blobs
- Check remaining quota against file size before starting an upload
- Alert users after plan downgrades when usage exceeds the new limit
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)