thedotmack/claude-mem · error
sync hub status: projected_seq exceeds head_seq
Error message
sync hub status: projected_seq exceeds head_seq
What it means
Thrown after epoch/head_seq/projected_seq are individually validated as canonical decimals, when compareCanonicalDecimals(projectedSeq, headSeq) > 0 — i.e. the hub claims a projected sequence greater than its committed head. This violates the checkpoint invariant (projected_seq <= head_seq is not required in general, but here projected must not exceed head). It indicates hub-side corruption or a logic error, not a client mistake.
Source
Thrown at src/services/sync/CloudSync.ts:623
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error('sync hub status: response must be an object');
}
const record = parsed as Record<string, unknown>;
if (record.protocol_version !== 2) {
throw new Error('sync hub status: response requires protocol_version 2');
}
if (
typeof record.epoch !== 'string'
|| typeof record.head_seq !== 'string'
|| typeof record.projected_seq !== 'string'
) {
throw new Error('sync hub status: response requires decimal-string epoch/head_seq/projected_seq');
}
const epoch = assertCanonicalDecimal(record.epoch, { positive: true });
const headSeq = assertCanonicalDecimal(record.head_seq);
const projectedSeq = assertCanonicalDecimal(record.projected_seq);
if (compareCanonicalDecimals(projectedSeq, headSeq) > 0) {
throw new Error('sync hub status: projected_seq exceeds head_seq');
}
this.hubStatus = {
checkedAt,
reachable: true,
epoch,
headSeq,
projectedSeq,
error: null,
};
} catch (error) {
const raw = error instanceof Error ? error.message : String(error);
const safe = this.token === '' ? raw : raw.split(this.token).join('[REDACTED]');
this.hubStatus = {
checkedAt,
reachable: false,
epoch: null,
headSeq: null,
projectedSeq: null,View on GitHub (pinned to d768ba3643)
Solutions
- Retry the status probe once — a transient inconsistent response may self-correct.
- If it persists, the hub is in a corrupt/inconsistent state; report to the hub operator with the epoch/head_seq/projected_seq values.
- Do not attempt to push/pull against a hub in this state, as sequence assumptions are violated.
- Confirm the client is not pointed at a stale/read-only hub replica divergent from the primary.
Defensive patterns
Strategy: try-catch
Type guard
function isHubProjectedExceedsHead(e: unknown): boolean {
return e instanceof Error && /sync hub status: projected_seq exceeds head_seq/i.test(e.message);
} Try / catch
try { await cloudSync.status(); }
catch (e) {
if (isHubProjectedExceedsHead(e)) {
await sleep(2000); // give an inconsistent hub a moment to settle
try { return await cloudSync.status(); } catch { markHubCorrupt(e.message); return; }
}
throw e;
} Prevention
- Do not push/pull against a hub returning projected_seq > head_seq; treat it as corrupt.
- Report persistent occurrences to the hub operator with the epoch/head/projected values.
- Ensure you are not reading from a stale, divergent hub replica.
- Add monitoring that flags this invariant break immediately.
When it happens
Trigger: The hub returned a status where projected_seq > head_seq, which is logically impossible in a correct monotonic sequencer. Possible if the hub had a rollback bug, mixed two epochs, or emitted stale cached fields inconsistently.
Common situations: Hub bug after a partial write/rollback; hub restarting mid-assignment and emitting inconsistent head/projected; a misbehaving hub replica returning cached divergent state.
Related errors
- sync hub status ${response.status}: ${body}
- sync hub status: response is not JSON
- sync hub status: response must be an object
- sync hub status: response requires protocol_version 2
- sync hub status: response requires decimal-string epoch/head
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/1aec00fc157a2e19.
Report an issue: GitHub.