toeverything/AFFiNE · error · DocNotFound

doc_not_found

doc_not_found

Error message

Doc ${docId} under Space ${spaceId} not found.

What it means

Thrown by the deprecated WorkspaceType.pageMeta resolver when this.models.doc.getAuthors(workspace.id, pageId) returns null - the doc has no author metadata row, so the page effectively does not exist in this workspace. DocNotFound is a resource_not_found error carrying spaceId and docId.

Source

Thrown at packages/backend/server/src/core/workspaces/resolvers/doc.ts:366

      );
    }
  }

  @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 26c515e050)

Solutions

  1. Switch to the non-deprecated WorkspaceType.doc resolver (the resolver is marked deprecated in favor of [WorkspaceType.doc]).
  2. Confirm the pageId exists in the workspace (e.g. via the doc list) before requesting metadata.
  3. If the row is genuinely missing, trigger a doc re-index/rebuild for that workspace.
  4. Handle the error gracefully in the UI and refresh the doc list.

Example fix

# before
query { workspace { pageMeta(pageId: $id) { createdAt } } }

# after - use the non-deprecated resolver
query { workspace { doc(workspaceId: $wid, docId: $id) { ... } } }
Defensive patterns

Strategy: validation

Validate before calling

// Verify the page exists before resolving its metadata
const exists = await gql.docExists(workspaceId, pageId);
if (!exists) throw new Error('Page does not exist - skip pageMeta');

Type guard

function isDocNotFound(e: unknown): boolean {
  return (
    typeof e === 'object' &&
    e !== null &&
    (e as any).extensions?.code === 'doc_not_found'
  );
}

Try / catch

try {
  return await gql.pageMeta(workspaceId, pageId);
} catch (e) {
  if (isDocNotFound(e)) {
    // page was deleted; refresh the doc list and drop the stale reference
    await refetchDocList();
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Querying the pageMeta field on a workspace for a pageId that was never created, was deleted, or whose metadata row is missing; access control passed (Doc.Read) but the underlying author record is absent.

Common situations: Stale client referencing a docId that was removed; sync race where the doc exists in the updates table but not in the authors/materialized view; deleted page still cached on the client; wrong pageId typed in.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/523e8fba4e58407b. Report an issue: GitHub.