toeverything/AFFiNE · error · DocNotFound
doc_not_found
doc_not_found
Error message
Doc ${docId} under Space ${spaceId} not found. What it means
In rollbackDoc, after the target history snapshot is found, the current doc snapshot is loaded via getDocSnapshot. If the doc has no current snapshot row, rollback cannot capture a pre-rollback history record, so it throws DocNotFound (resource_not_found / doc_not_found) with spaceId and docId.
Solutions
- Confirm the doc exists and is readable via the doc read API before offering rollback
- Wait for or manually trigger the snapshot merge job so a current snapshot exists
- Check the arguments: the first parameter is spaceId (workspace id), the second is docId
- If the doc was deleted, remove it from the client's local state instead of rolling back
Example fix
// before
await docAdapter.rollbackDoc(spaceId, docId, ts);
// after
const snap = await docAdapter.getDocSnapshot(spaceId, docId);
if (!snap) {
throw new Error(`doc ${docId} missing snapshot; wait for merge or recreate doc`);
}
await docAdapter.rollbackDoc(spaceId, docId, ts); Defensive patterns
Strategy: validation
Validate before calling
const snapshot = await docAdapter.getDocSnapshot(spaceId, docId);
if (!snapshot?.bin) {
throw new Error(`doc ${docId} has no snapshot; cannot roll back`);
}
await rollbackDoc(spaceId, docId, ts); Type guard
function isDocNotFound(e: unknown): boolean {
return (e as { extensions?: { code?: string } }).extensions?.code === 'doc_not_found';
} Try / catch
try {
await rollbackDoc(spaceId, docId, ts);
} catch (e) {
if (isDocNotFound(e)) {
removeDocFromLocalState(docId); // doc deleted; drop stale reference
return;
}
throw e;
} Prevention
- Check the doc still exists before exposing history actions
- Keep argument order straight: (spaceId, docId, timestamp, editorId)
- Wait for the snapshot merge job on newly created docs before offering rollback
When it happens
Trigger: Rolling back a doc that was deleted (snapshot rows removed with the workspace/doc); a doc that only has pending updates but whose snapshot merge job (doc.mergePendingDocUpdates) has never produced a snapshot; passing a docId from a different workspace or swapping spaceId/docId arguments.
Common situations: Stale doc references in a client after another user deleted the doc; rolling back immediately after doc creation on a heavily delayed job queue; scripts built against older API signatures where spaceId and docId positions were swapped.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- doc_history_not_found
- Can not find the current version of the doc.
- Can not find the version to rollback to.
- doc_history_not_found
- doc_not_found
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/e863e5f3bfbf1ccb.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/doc/adapters/workspace.ts:267
};
}
override async rollbackDoc(
spaceId: string,
docId: string,
timestamp: number,
editorId?: string
): Promise<void> {
await using _lock = await this.lockDocForUpdate(spaceId, docId);
const toSnapshot = await this.getDocHistory(spaceId, docId, timestamp);
if (!toSnapshot) {
throw new DocHistoryNotFound({ spaceId, docId, timestamp });
}
const fromSnapshot = await this.getDocSnapshot(spaceId, docId);
if (!fromSnapshot) {
throw new DocNotFound({ spaceId, docId });
}
// force create a new history record after rollback
await this.createDocHistory(
{
...fromSnapshot,
// override the editor to the one who requested the rollback
editor: editorId,
},
true
);
// WARN:
// we should never do the snapshot updating in recovering,
// which is not the solution in CRDT.
// let user revert in client and update the data in sync system
// const change = this.generateChangeUpdate(fromSnapshot.bin, toSnapshot.bin);
// await this.pushDocUpdates(spaceId, docId, [change]);
View on GitHub (pinned to 2af30773ae)