toeverything/AFFiNE · error · Error
Can not find the version to rollback to.
Error message
Can not find the version to rollback to.
What it means
Thrown during rollbackDoc when getDocHistory(spaceId, docId, timestamp) returns no snapshot for the requested timestamp. The rollback algorithm needs a 'from' (current) and 'to' (target) snapshot to compute a delta update; without the target it cannot generate the change. This is a plain `new Error` and surfaces as a 500 unless the resolver wraps it.
Source
Thrown at packages/backend/server/src/core/doc/storage/doc.ts:248
abstract pushDocUpdates(
spaceId: string,
docId: string,
updates: Uint8Array[],
editorId?: string
): Promise<number>;
abstract deleteDoc(spaceId: string, docId: string): Promise<void>;
abstract deleteSpace(spaceId: string): Promise<void>;
async rollbackDoc(
spaceId: string,
docId: string,
timestamp: number,
editorId?: string
): Promise<void> {
await using _lock = await this.lockDocForUpdate(spaceId, docId);
const toSnapshot = await this.getDocHistory(spaceId, docId, timestamp);
if (!toSnapshot) {
throw new Error('Can not find the version to rollback to.');
}
const fromSnapshot = await this.getDocSnapshot(spaceId, docId);
if (!fromSnapshot) {
throw new Error('Can not find the current version of the doc.');
}
const change = this.generateChangeUpdate(fromSnapshot.bin, toSnapshot.bin);
await this.pushDocUpdates(spaceId, docId, [change], editorId);
// force create a new history record after rollback
await this.createDocHistory(fromSnapshot, true);
}
abstract getSpaceDocTimestamps(
spaceId: string,
after?: number
): Promise<Record<string, number> | null>;View on GitHub (pinned to 26c515e050)
Solutions
- Before rollback, fetch the available history list for the doc and pass only a timestamp that appears in it (the UI should already restrict to known snapshots).
- Increase the history retention window / snapshot cadence if legitimate old versions are being requested and pruned too aggressively.
- Verify the spaceId/docId match the doc whose history the user is browsing; a wrong workspace header is a frequent cause.
- Convert this to a typed NotFound-style error (e.g. extend a RollbackTargetNotFound) and map to 404 at the resolver so the client can render a clean 'version no longer available' message.
Example fix
// before
const toSnapshot = await this.getDocHistory(spaceId, docId, timestamp);
if (!toSnapshot) {
throw new Error('Can not find the version to rollback to.');
}
// after
const toSnapshot = await this.getDocHistory(spaceId, docId, timestamp);
if (!toSnapshot) {
throw new NotFoundException(
`No history snapshot for doc ${docId} at ${new Date(timestamp).toISOString()}`
);
} Defensive patterns
Strategy: validation
Validate before calling
async function getValidRollbackTarget(storage, ws, doc, ts) {
const history = await storage.getDocHistoryList(ws, doc); // list available snapshots
const match = history.find(h => h.timestamp === ts);
if (!match) {
throw new UserError(`No snapshot at ${ts}; pick from ${history.map(h => h.timestamp).join(',')}`);
}
return match;
} Type guard
function isRollbackTargetMissing(e: unknown): boolean {
return e instanceof Error && e.message === 'Can not find the version to rollback to.';
} Try / catch
try {
await doc.rollbackDoc(ws, doc, ts);
} catch (e) {
if (isRollbackTargetMissing(e)) {
return res.status(404).send('That version is no longer available');
}
throw e;
} Prevention
- Only offer timestamps returned by the history list endpoint.
- Tune history retention to match user expectations of how far back they can roll.
- Pass server-side UTC timestamps, not client-local times.
When it happens
Trigger: Calling rollback with a timestamp older than the oldest retained history record, a timestamp in the future, a timestamp for a doc whose history was pruned/garbage-collected, or a docId/spaceId mismatch where history simply doesn't exist for that pair.
Common situations: History retention policy trimmed old snapshots below the requested timestamp. Clock skew between client (which picked a timestamp from a UI timeline) and server. Doc was imported/migrated and has no history lineage. A user picked a history entry from a different doc.
Related errors
- doc_history_not_found
- doc_not_found
- Can not find the current version of the doc.
- Workspace ${workspaceId} not found or has no root document
- Document ${docId} not found
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/d106c5d7d03afbdf.
Report an issue: GitHub.