toeverything/AFFiNE · error · NotFoundException
Document ${docId} not found
Error message
Document ${docId} not found What it means
NotFoundException thrown by updateDoc (markdown path) when getDoc returns no bin for the given docId. The updater needs the existing binary to compute a structural delta via updateDocWithMarkdown; without it there is nothing to diff against. Correctly typed as NotFoundException.
Source
Thrown at packages/backend/server/src/core/doc/writer.ts:162
* @param workspaceId - The workspace ID
* @param docId - The document ID to update
* @param markdown - The new markdown content
* @param editorId - Optional editor ID for tracking
*/
async updateDoc(
workspaceId: string,
docId: string,
markdown: string,
editorId?: string
): Promise<UpdateDocResult> {
this.logger.debug(
`Updating doc ${docId} in workspace ${workspaceId} from markdown`
);
// Fetch existing document
const existingDoc = await this.storage.getDoc(workspaceId, docId);
if (!existingDoc?.bin) {
throw new NotFoundException(`Document ${docId} not found`);
}
// Compute delta update using structural diff
// Use zero-copy buffer view when possible for native function
const existingBinary = Buffer.isBuffer(existingDoc.bin)
? existingDoc.bin
: Buffer.from(
existingDoc.bin.buffer,
existingDoc.bin.byteOffset,
existingDoc.bin.byteLength
);
const delta = updateDocWithMarkdown(existingBinary, markdown, docId);
// Push only the delta changes
const timestamp = await this.storage.pushDocUpdates(
workspaceId,
docId,
[delta],View on GitHub (pinned to 26c515e050)
Solutions
- Have the client re-fetch the doc list and only allow 'update' on docIds present in the current list.
- Treat 404 as 'doc deleted elsewhere' and surface a reconciliation prompt rather than letting the user retry blindly.
- If the doc should exist, verify its snapshot row in storage and re-materialize if missing.
- Return the docId in the error payload so the client can log/trace which doc failed.
Example fix
// before
const existingDoc = await this.storage.getDoc(workspaceId, docId);
if (!existingDoc?.bin) {
throw new NotFoundException(`Document ${docId} not found`);
}
// after
const existingDoc = await this.storage.getDoc(workspaceId, docId);
if (!existingDoc) {
throw new NotFoundException(`Document ${docId} does not exist in workspace ${workspaceId}`);
}
if (!existingDoc.bin) {
throw new ConflictException(`Document ${docId} snapshot is empty; re-import required`);
} Defensive patterns
Strategy: validation
Validate before calling
async function assertDocExists(storage, ws, doc) {
const d = await storage.getDoc(ws, doc);
if (!d?.bin) throw new UserError(`Doc ${doc} not found`);
return d;
} Type guard
import { NotFoundException } from '@nestjs/common';
function isDocNotFound(e: unknown, docId: string): boolean {
return e instanceof NotFoundException && e.message.includes(`Document ${docId} not found`);
} Try / catch
try {
await writer.updateDoc(ws, doc, md);
} catch (e) {
if (isDocNotFound(e, doc)) { res.status(404).send('Doc deleted elsewhere'); return; }
throw e;
} Prevention
- Refresh the doc list before allowing edits.
- Handle 404 by reconciling local state, not by silent retry.
- Refrain from optimistic edits on docs that may have been removed.
When it happens
Trigger: Updating a docId that doesn't exist in the workspace, was deleted, or whose snapshot bin is empty. Cross-workspace docId reuse. Updating immediately after deletion before the client refreshed.
Common situations: Stale client holding a reference to a deleted doc. Doc was moved/merged and the old id no longer resolves. Storage partial write left the row without bin. Race between delete and update.
Related errors
- Can not find the version to rollback to.
- Workspace ${workspaceId} not found or has no root document
- Can not find the current version of the doc.
- No metadata provided
- notification_not_found
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/306d1cabe7063a67.
Report an issue: GitHub.