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

  1. Query the doc itself (the WorkspaceType.doc field) first and handle a null doc before asking for metadata
  2. Migrate off the deprecated pageMeta field — the deprecation reason points to WorkspaceType.doc
  3. 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

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


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)