toeverything/AFFiNE · error · DocNotFound

doc_not_found

doc_not_found

Error message

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

What it means

Thrown by WorkspacesController.getDocBinaryOrThrow when DocReader.getDoc(workspaceId, docId) resolves null — after permission checks passed, the server could not load any binary/update data for that doc id in that workspace. It is the not-found signal of the doc storage layer (snapshots/updates plus blob backing).

Solutions

  1. Verify the doc exists via doc meta / workspace doc list before fetching its binary
  2. Check the workspaceId/docId pair — the same guid in the wrong space is not found
  3. If storage was wiped or migrated, restore snapshots/updates or re-create the doc
  4. Server-side, trace DocReader.getDoc dependencies (snapshot + update models, storage) to see which layer returns null for the pair
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the doc exists before fetching its binary
const meta = await getDocMeta(wsId, docId);
if (!meta) {
  handleDocGone(docId);
  return;
}

Type guard

function isDocNotFound(e: unknown): e is { code: 'doc_not_found'; docId: string; spaceId: string } {
  return typeof e === 'object' && e !== null && (e as any).code === 'doc_not_found';
}

Try / catch

try {
  return await getDocBinary(wsId, docId);
} catch (e) {
  if (isDocNotFound(e)) {
    removeDocFromLocalCache(e.docId); // stale id — stop retrying
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Internal doc-binary fetches (getDocBinaryOrThrow callers) where the doc was deleted, its snapshots/updates were never written or were garbage-collected, or the guid simply does not exist in that workspace.

Common situations: Client holding a stale docId after the doc was deleted in another session; workspace data pruned or migrated without snapshots; copy-pasted wrong guid; snapshot/update storage (S3, database) misconfigured so reads return null; doc created but its first sync never completed.

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/b3f7b50c055db3d3. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/workspaces/controller.ts:90

    }
  }

  private async getPublishModeHeader(workspaceId: string, docId: string) {
    const docMeta = await this.models.doc.getMeta(workspaceId, docId, {
      select: {
        mode: true,
      },
    });
    return docMeta?.mode === PublicDocMode.Edgeless
      ? DocMode.edgeless
      : DocMode.page;
  }

  private async getDocBinaryOrThrow(workspaceId: string, docId: string) {
    const binResponse = await this.docReader.getDoc(workspaceId, docId);

    if (!binResponse) {
      throw new DocNotFound({
        spaceId: workspaceId,
        docId,
      });
    }

    return binResponse;
  }

  @Public()
  @Get('/:id/blob-manifest/v1')
  async blobManifestV1(
    @CurrentUser() user: CurrentUser | undefined,
    @Param('id') workspaceId: string,
    @Query('sourceType') sourceType: string,
    @Query('docId') docId: string,
    @Query('timestampMs') timestampMs: string | undefined,
    @Res() res: Response
  ) {

View on GitHub (pinned to 2af30773ae)