toeverything/AFFiNE · error · NotFound
not_found
not_found
Error message
Doc not found
What it means
Thrown by the internal RPC handler `GET /rpc/workspaces/:workspaceId/docs/:docId` when `docReader.getDoc(workspaceId, docId)` returns null. The endpoint is `@Internal()` (server-to-server) and maps the missing doc to `NotFound` with code `not_found`, which the global filter turns into HTTP 404.
Source
Thrown at packages/backend/server/src/core/doc-service/controller.ts:33
import { DatabaseDocReader } from '../doc';
@Controller('/rpc')
export class DocRpcController {
private readonly logger = new Logger(DocRpcController.name);
constructor(private readonly docReader: DatabaseDocReader) {}
@SkipThrottle()
@Internal()
@Get('/workspaces/:workspaceId/docs/:docId')
async getDoc(
@Param('workspaceId') workspaceId: string,
@Param('docId') docId: string,
@Res() res: Response
) {
const doc = await this.docReader.getDoc(workspaceId, docId);
if (!doc) {
throw new NotFound('Doc not found');
}
this.logger.debug(
`get doc ${docId} from workspace ${workspaceId}, size: ${doc.bin.length}`
);
res.setHeader('x-doc-timestamp', doc.timestamp.toString());
if (doc.editor) {
res.setHeader('x-doc-editor-id', doc.editor);
}
res.send(doc.bin);
}
@SkipThrottle()
@Internal()
@Get('/workspaces/:workspaceId/docs/:docId/markdown')
async getDocMarkdown(
@Param('workspaceId') workspaceId: string,
@Param('docId') docId: string,
@Query('aiEditable') aiEditable?: stringView on GitHub (pinned to 26c515e050)
Solutions
- On the caller side, treat HTTP 404 from this RPC as 'doc absent' and trigger first-create or skip, not as a hard failure.
- Verify the doc row exists in the workspace's `doc` table before issuing the RPC for known-existing docs.
- Confirm `workspaceId`/`docId` are well-formed and paired (doc belongs to that workspace).
- If the doc was just created, retry shortly to allow the snapshot write to land.
Example fix
// before
const res = await fetch(`/rpc/workspaces/${wid}/docs/${did}`);
const bin = await res.arrayBuffer();
// after
const res = await fetch(`/rpc/workspaces/${wid}/docs/${did}`);
if (res.status === 404) {
// doc absent — caller decides: seed it or skip
return null;
}
if (!res.ok) throw new Error(`doc rpc failed: ${res.status}`);
const bin = await res.arrayBuffer(); Defensive patterns
Strategy: try-catch
Validate before calling
// Internal RPC caller: confirm the snapshot row exists before requesting
async function docSnapshotExists(workspaceId: string, docId: string): Promise<boolean> {
const row = await models.doc.get(workspaceId, docId);
return row != null;
}
if (!(await docSnapshotExists(workspaceId, docId))) {
// doc not seeded yet — handle as 'absent', not an error
return null;
} Type guard
function isDocBytes(value: unknown): value is { bin: Uint8Array; timestamp: number } {
return typeof value === 'object' && value !== null &&
(value as { bin?: unknown }).bin instanceof Uint8Array &&
typeof (value as { timestamp?: unknown }).timestamp === 'number';
} Try / catch
try {
const res = await fetch(`/rpc/workspaces/${wid}/docs/${did}`);
if (res.status === 404) return null; // doc absent — caller decides
if (!res.ok) throw new Error(`doc rpc failed: ${res.status}`);
return await res.arrayBuffer();
} catch (e) {
// network-level errors: retry/backoff as appropriate
throw e;
} Prevention
- Treat HTTP 404 from `/rpc/.../docs/:docId` as 'doc absent', not a hard failure.
- Verify the snapshot row exists for known docs before calling.
- Retry shortly after doc creation to let the snapshot write land.
- Validate `workspaceId`/`docId` pairing and format.
When it happens
Trigger: A peer service (sync/collab) requesting a doc that was never created, was deleted, or whose binary snapshot row is missing in the `doc` table for that workspace.
Common situations: Sync requests arriving before the doc snapshot is written; a deleted doc still referenced by cached routing; workspace migration that dropped rows; a malformed `docId`.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/72c8300fd24b2d73.
Report an issue: GitHub.