thedotmack/claude-mem · error
sync hub push: sent operation is not covered by…
Error message
sync hub push: sent operation is not covered by projected_seq
What it means
An acked operation's seq exceeds the response's projected_seq — the acknowledgment is not covered by the projection checkpoint, breaking the core promise that 200 is returned only when the checkpoint covers every acknowledged commit. Caught in validatePushResponse before any local stamping; flush() backs off and retries the same ops (hub dedupe keeps this safe).
Solutions
- Check hub metrics/logs for projection lag at the time of the failure
- Restore the gate: the hub must not answer 200 until projected_seq >= every ack.seq it returns
- If projection advance is failing (worker crash, Pro errors), fix that root cause first
- Clients self-heal via retry once the hub honors the checkpoint gate again
Defensive patterns
Strategy: validation
Validate before calling
// Hub-side gate: 200 only when the checkpoint covers every ack:
function checkpointCoversAcks(acked: { seq: string }[], projected_seq: string): boolean {
return acked.every(a => BigInt(a.seq) <= BigInt(projected_seq));
}
// if (!checkpointCoversAcks(...)) await waitForProjection(minAckSeq) before responding Type guard
function acksCoveredByCheckpoint(acked: { seq: string }[], projected_seq: string): boolean {
return acked.every(a => BigInt(a.seq) <= BigInt(projected_seq));
} Try / catch
if (/not covered by projected_seq/.test(sync.status().lastError ?? '')) {
// hub returned 200 too early: projection gate broken or projection worker failing; check hub logs
} Prevention
- Make projection advancement part of the push commit path, not fire-and-forget
- Alert on hub projection lag; a lagging projection turns this into a hard sync stall
- Verify the gate survives hub restarts and partial projection replays
When it happens
Trigger: Hub emits acks from the append path but projected_seq from a lagging projection worker; projection advance fails silently and the response path doesn't wait on it; field computation order bug in the response builder.
Common situations: Hub under heavy load where the projection falls behind and the 200 gate was relaxed; a hub change that made projection fire-and-forget; partial deployment mixing gated and ungated response paths.
Related errors
- sync hub push: checkpoint order requires head_seq <=…
- sync hub push: acknowledgment seq exceeds head_seq
- sync hub push: distinct operation tuples claimed the same…
- projection_error: invalid projected through_seq
- sync hub push: 200 response acknowledgment multiplicity…
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/eb84ae8334d95a79.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/CloudSync.ts:1077
throw new Error(
`sync hub push: 200 response acknowledgment multiplicity mismatch (expected ${expected}, received ${actual})`
);
}
}
if (ackCounts.size !== sentCounts.size) {
// Defensive: the unknown-tuple branch above should make this impossible.
throw new Error('sync hub push: 200 response acknowledgment multiset mismatch');
}
if (compareCanonicalDecimals(response.head_seq, response.projected_seq) > 0) {
throw new Error('sync hub push: checkpoint order requires head_seq <= projected_seq');
}
for (const ack of response.acked) {
if (compareCanonicalDecimals(ack.seq, response.head_seq) > 0) {
throw new Error('sync hub push: acknowledgment seq exceeds head_seq');
}
if (compareCanonicalDecimals(ack.seq, response.projected_seq) > 0) {
throw new Error('sync hub push: sent operation is not covered by projected_seq');
}
}
}
/**
* Stamp rows / delete outbox entries for a fully validated acknowledgment
* multiset. The hub may return entries in any order.
*/
private stampAcked(acked: AckedOp[], pushed: WireOp[]): void {
const now = Date.now();
const bodies = new Map(pushed.map(op => {
const body = parseCanonicalOperation(op);
return [operationTupleKey({
id: body.id,
kind: body.kind,
entity_rev: body.entity_rev,
operation_sha256: op.operation_sha256,
}), { body, operationSha256: op.operation_sha256 }] as const;View on GitHub (pinned to e2d1df569a)