toeverything/AFFiNE · error · DocHistoryNotFound

doc_history_not_found

doc_history_not_found

Error message

History of ${docId} at ${timestamp} under Space ${spaceId}.

What it means

Thrown when getDocHistory returns no history snapshot for the given doc at the given timestamp. The doc exists but no historical version matching that time is available.

Source

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

      ts = new Date(timestamp);
    } catch {
      throw new InvalidHistoryTimestamp({ timestamp });
    }

    await this.ac.user(user.id).doc(ws, guid).assert('Doc.Read');

    const history = await this.workspace.getDocHistory(
      docId.workspace,
      docId.guid,
      ts.getTime()
    );

    if (history) {
      res.setHeader('content-type', 'application/octet-stream');
      res.setHeader('cache-control', 'private, max-age=2592000, immutable');
      res.send(history.bin);
    } else {
      throw new DocHistoryNotFound({
        spaceId: docId.workspace,
        docId: guid,
        timestamp: ts.getTime(),
      });
    }
  }

  @Get('/:id/docs/:docId/comment-attachments/:key')
  @CallMetric('controllers', 'workspace_get_comment_attachment')
  async commentAttachment(
    @CurrentUser() user: CurrentUser,
    @Param('id') workspaceId: string,
    @Param('docId') docId: string,
    @Param('key') key: string,
    @Res() res: Response
  ) {
    await this.ac.user(user.id).doc(workspaceId, docId).assert('Doc.Read');

View on GitHub (pinned to 26c515e050)

Solutions

  1. Use a timestamp within the retained history window.
  2. Confirm history/snapshot jobs are enabled and running.
  3. Check history storage retention settings.
  4. Fall back to the current doc version if no history exists.

Example fix

// before
const h = await workspace.getDocHistory(ws, guid, ts.getTime())
res.send(h.bin)
// after
const h = await workspace.getDocHistory(ws, guid, ts.getTime())
if (!h) throw new NotFound('no history at this time')
Defensive patterns

Strategy: try-catch

Validate before calling

const historyList = await workspace.listDocHistory(ws, guid)
if (!historyList.some(h => Math.abs(h.timestamp - ts) < SNAP_GAP)) return noHistoryState()

Try / catch

try { await restoreHistory(guid, ts) } catch (e) {
  if (e.code === 'doc_history_not_found') showNoHistory()
  else throw e
}

Prevention

When it happens

Trigger: Requesting doc history at a timestamp older than retained history, newer than now, in a snapshot gap, or when history snapshots are disabled/not collected for the workspace.

Common situations: History retention window expired; snapshot job failed/disabled; timestamp in the future or before doc creation; time-travel on a brand-new doc.

Related errors


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