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

  1. Retry the status probe once — a transient inconsistent response may self-correct.
  2. If it persists, the hub is in a corrupt/inconsistent state; report to the hub operator with the epoch/head_seq/projected_seq values.
  3. Do not attempt to push/pull against a hub in this state, as sequence assumptions are violated.
  4. 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

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


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/1aec00fc157a2e19. Report an issue: GitHub.