toeverything/AFFiNE · error · DocNotFound
doc_not_found
doc_not_found
Error message
Doc ${docId} under Space ${spaceId} not found. What it means
The deprecated Workspace.pageMeta resolver loads author metadata with models.doc.getAuthors; a null result means no cloud doc record exists for (workspaceId, pageId) — the page was never synced to the cloud, was deleted, or the id is not a doc in that space. Doc.Read can pass at workspace scope even though the doc row itself is absent, so the missing metadata is what surfaces.
Solutions
- Query the doc itself (the WorkspaceType.doc field) first and handle a null doc before asking for metadata
- Migrate off the deprecated pageMeta field — the deprecation reason points to WorkspaceType.doc
- Ensure the page is synced to the cloud before requesting cloud metadata
Example fix
# before (GraphQL)
query meta($wsId: String!, $pageId: String!) {
workspace(id: $wsId) {
pageMeta(pageId: $pageId) { createdAt updatedAt } # throws DOC_NOT_FOUND for unknown ids
}
}
# after
query doc($wsId: String!, $pageId: String!) {
workspace(id: $wsId) {
doc(pageId: $pageId) { # returns null instead of throwing
meta { createdAt updatedAt }
}
}
} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the doc exists before asking the deprecated pageMeta field
const doc = await workspaceDoc(ws.id, pageId);
if (!doc) {
handleMissingPage(pageId);
} else {
const meta = await pageMeta(ws.id, pageId);
} Type guard
function isDocNotFound(e: unknown): boolean {
return (
typeof e === 'object' && e !== null &&
(e as { extensions?: { code?: string } }).extensions?.code === 'doc_not_found'
);
} Try / catch
try {
meta = await pageMeta(ws.id, pageId);
} catch (e) {
if (isDocNotFound(e)) {
dropPageFromCache(pageId); // doc is gone; stop requesting its metadata
} else throw e;
} Prevention
- Prefer the WorkspaceType.doc field over the deprecated pageMeta resolver
- Validate page ids from URLs/deep links against the synced doc list before querying cloud metadata
- Purge local references to deleted docs when the doc list refreshes
When it happens
Trigger: Querying pageMeta(pageId) with an id that has no doc record in that workspace; the doc being deleted between the permission check and the metadata load; a local-only page that was never synced to the cloud.
Common situations: Clients still on the deprecated pageMeta field; deep links or bookmarks holding stale page ids; races right after doc deletion.
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
- member_not_found_in_space
- user_not_found
- action_forbidden
- action_forbidden_on_non_team_workspace
- already_in_space
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/523e8fba4e58407b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/workspaces/resolvers/doc.ts:335
private readonly event: EventBus,
private readonly runtime: BackendRuntimeProvider
) {}
@ResolveField(() => WorkspaceDocMeta, {
description: 'Cloud page metadata of workspace',
complexity: 2,
deprecationReason: 'use [WorkspaceType.doc] instead',
})
async pageMeta(
@CurrentUser() me: CurrentUser,
@Parent() workspace: WorkspaceType,
@Args('pageId') pageId: string
) {
await this.ac.user(me.id).doc(workspace.id, pageId).assert('Doc.Read');
const metadata = await this.models.doc.getAuthors(workspace.id, pageId);
if (!metadata) {
throw new DocNotFound({ spaceId: workspace.id, docId: pageId });
}
return {
createdAt: metadata.createdAt,
updatedAt: metadata.updatedAt,
createdBy: metadata.createdByUser || null,
updatedBy: metadata.updatedByUser || null,
};
}
@ResolveField(() => [DocType], {
description: 'Get public docs of a workspace',
complexity: 2,
})
async publicDocs(@Parent() workspace: WorkspaceType) {
return this.models.doc.findPublics(workspace.id);
}
View on GitHub (pinned to 2af30773ae)