toeverything/AFFiNE · warning · InvalidHistoryTimestamp
invalid_history_timestamp
invalid_history_timestamp
Error message
Invalid doc history timestamp provided.
What it means
Intended to fire when the history timestamp path param cannot be parsed. NOTE: the current implementation is effectively unreachable because `new Date(timestamp)` never throws; an unparseable string yields an Invalid Date whose getTime() is NaN. So malformed timestamps pass this guard and surface later as an empty history lookup instead of InvalidHistoryTimestamp.
Source
Thrown at packages/backend/server/src/core/workspaces/controller.ts:350
res.setHeader('content-type', 'application/octet-stream');
res.send(publicRootDoc);
}
@Get('/:id/docs/:guid/histories/:timestamp')
@CallMetric('controllers', 'workspace_get_history')
async history(
@CurrentUser() user: CurrentUser,
@Param('id') ws: string,
@Param('guid') guid: string,
@Param('timestamp') timestamp: string,
@Res() res: Response
) {
const docId = new DocID(guid, ws);
let ts;
try {
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,View on GitHub (pinned to 26c515e050)
Solutions
- Validate the timestamp client-side before calling (Date.parse + Number.isFinite).
- Fix the server guard to check Number.isNaN(ts.getTime()) instead of relying on a throw.
- Send timestamps as UTC ISO 8601 or integer epoch milliseconds.
- URL-encode the timestamp segment.
Example fix
// before (server)
try { ts = new Date(timestamp) } catch { throw new InvalidHistoryTimestamp({ timestamp }) }
// after (server)
ts = new Date(timestamp)
if (Number.isNaN(ts.getTime())) throw new InvalidHistoryTimestamp({ timestamp }) Defensive patterns
Strategy: validation
Validate before calling
function validHistoryTimestamp(ts: string): boolean {
const t = Date.parse(ts)
return Number.isFinite(t)
} Type guard
function isValidTimestamp(v: string): v is string {
return Number.isFinite(Date.parse(v))
} Try / catch
try { await fetchHistory(guid, ts) } catch (e) {
if (e.code === 'invalid_history_timestamp') promptValidDate()
else throw e
} Prevention
- Always validate timestamps before sending.
- Use ISO 8601 UTC.
- URL-encode path segments.
- On the server, check Number.isNaN(ts.getTime()) since Date never throws.
When it happens
Trigger: Calling the doc history endpoint with a timestamp path param the author expected to fail Date parsing (e.g. 'abc', '2024-13-99'). In practice the catch does not trigger; the request proceeds with NaN and returns no history.
Common situations: Client sends a non-ISO string, a malformed epoch, or an empty timestamp segment due to a URL construction bug.
Related errors
- Invalid rowId
- doc_history_not_found
- doc_not_found
- Can not find the version to rollback to.
- No metadata provided
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/b251d365413f729c.
Report an issue: GitHub.