toeverything/AFFiNE · error · BlobNotFound
blob_not_found
blob_not_found
Error message
Blob ${blobId} not found in Space ${spaceId}. What it means
Thrown by the workspace blob route when storage.get(workspaceId, name, true) returns neither a body nor a redirectUrl — the named blob object does not exist in the workspace's blob storage. Permission already passed; this is a pure storage-layer miss.
Solutions
- Verify the blob key exists (blobs list API or the storage backend) before linking it
- Re-upload the missing blob and update the referencing doc
- If objects vanish systematically, audit storage provider config (bucket, prefix) and any GC job
- Watch for the route's 'has no metadata' warning in logs — it flags half-written objects
Defensive patterns
Strategy: try-catch
Type guard
function isBlobNotFound(e: unknown): e is { code: 'blob_not_found'; spaceId: string; blobId: string } {
return typeof e === 'object' && e !== null && (e as any).code === 'blob_not_found';
} Try / catch
try {
return await fetchBlob(wsId, blobKey);
} catch (e) {
if (isBlobNotFound(e)) {
return placeholderImage(e.blobId); // media gone — degrade gracefully, no retry
}
throw e;
} Prevention
- Validate blob keys exist (list API / storage head) before persisting them in doc content
- Don't run aggressive GC against blobs still referenced by docs
- When migrating storage, verify object counts match the metadata store
- Treat upload failures as fatal for the referencing content so half-written blobs aren't linked
When it happens
Trigger: GET /api/workspaces/:id/blobs/:name with a name never uploaded, deleted, or whose object is missing from the backend even though the URL was well-formed (no signed-url redirect available either).
Common situations: Stale blob references in doc content after blob garbage collection; storage bucket wiped or migrated without copying objects; truncated/typo'd blob key; upload recorded in the metadata store but the object write failed.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/603e2457f3526139.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/workspaces/controller.ts:137
const { body, metadata, redirectUrl } = await this.storage.get(
workspaceId,
name,
true
);
if (redirectUrl) {
// redirect to signed url
if (redirect === 'manual') {
return res.send({
url: redirectUrl,
});
} else {
return res.redirect(redirectUrl);
}
}
if (!body) {
throw new BlobNotFound({
spaceId: workspaceId,
blobId: name,
});
}
// metadata should always exists if body is not null
if (metadata) {
res.setHeader(
'content-type',
metadata.contentType.startsWith('application/json') // application/json is reserved for redirect url
? 'text/json'
: metadata.contentType
);
res.setHeader('last-modified', metadata.lastModified.toUTCString());
res.setHeader('content-length', metadata.contentLength);
} else {
this.logger.warn(`Blob ${workspaceId}/${name} has no metadata`);
}View on GitHub (pinned to b4c8548c09)