thedotmack/claude-mem · error
sync hub push: 200 response contains an extra or mismatched
Error message
sync hub push: 200 response contains an extra or mismatched acknowledgment tuple
What it means
Thrown in validatePushResponse when an ack's operation-tuple key (JSON of [id, kind, entity_rev, operation_sha256]) does not match ANY tuple the client actually sent. The hub is acknowledging an operation the client never pushed, or the tuple identity diverged between send and ack. This is the canonical 'extra or mismatched ack' invariant — every ack must correspond to a sent op.
Source
Thrown at src/services/sync/CloudSync.ts:1039
const sentCounts = new Map<string, number>();
for (const op of pushed) {
const body = parseCanonicalOperation(op);
const key = operationTupleKey({
id: body.id,
kind: body.kind,
entity_rev: body.entity_rev,
operation_sha256: op.operation_sha256,
});
sentCounts.set(key, (sentCounts.get(key) ?? 0) + 1);
}
const ackCounts = new Map<string, number>();
const tupleSeq = new Map<string, string>();
const seqTuple = new Map<string, string>();
for (const ack of response.acked) {
const key = operationTupleKey(ack);
if (!sentCounts.has(key)) {
throw new Error('sync hub push: 200 response contains an extra or mismatched acknowledgment tuple');
}
ackCounts.set(key, (ackCounts.get(key) ?? 0) + 1);
const priorTupleSeq = tupleSeq.get(key);
if (priorTupleSeq !== undefined && priorTupleSeq !== ack.seq) {
throw new Error('sync hub push: duplicate operation tuple claimed different sequences');
}
tupleSeq.set(key, ack.seq);
const priorSeqTuple = seqTuple.get(ack.seq);
if (priorSeqTuple !== undefined && priorSeqTuple !== key) {
throw new Error('sync hub push: distinct operation tuples claimed the same sequence');
}
seqTuple.set(ack.seq, key);
}
for (const [key, expected] of sentCounts) {
const actual = ackCounts.get(key) ?? 0;View on GitHub (pinned to d768ba3643)
Solutions
- Compare the acked tuple (id, kind, entity_rev, operation_sha256) against the pushed WireOp bodies — operationTupleKey JSON-encodes all four; any single field diff triggers this.
- If the hub normalizes entity_rev or operation_sha256 (e.g. leading zeros, hash casing), make the hub preserve the exact client-supplied values.
- Verify the hub is not mixing in acks from concurrent push batches or other devices.
- Upgrade hub and client together to a matching tuple-identity contract.
Example fix
// before: pushed op { id:'obs-1', kind:'observation', entity_rev:'1', operation_sha256:'abc...' }
// but hub acks entity_rev:'01' (re-padded) -> tuple mismatch
// after: hub returns entity_rev exactly as sent ('1') so operationTupleKey matches Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that every ack you EXPECT can match a sent tuple is impossible
// (acks come from the hub). Instead ensure your pushed ops produce stable keys:
import { createHash } from 'crypto';
function stableSha256(buf: string): string {
return createHash('sha256').update(buf).digest('hex'); // identical on both sides
} Try / catch
try { await cloudSync.push(pushed); }
catch (e) {
if (e instanceof Error && e.message.includes('extra or mismatched acknowledgment tuple')) {
// log the sent vs acked tuple sets, leave outbox intact for retry
logger.error('SYNC', e.message, { sentCount: pushed.length }); return;
}
throw e;
} Prevention
- Ensure operation_sha256 is computed identically on client and hub (same encoding, casing, canonicalization).
- Do not let any intermediary (proxy/CDN) rewrite entity_rev or operation_sha256.
- Confirm the hub acks only ops from the current push batch, not other devices.
When it happens
Trigger: A 200 push response where at least one acked entry's (id, kind, entity_rev, operation_sha256) combination has no matching entry in the sentCounts multiset built from the pushed WireOp array. Reachable in validatePushResponse, which runs before any SQLite mutation in stampAcked.
Common situations: Hub rewrites operation_sha256 or entity_rev on its side (e.g. normalizing/padding), hub echoes back ops from a different device/batch, a proxy that recomputes hashes, or client/hub version skew where the tuple key components differ. The mismatch is almost always operation_sha256 or entity_rev differing.
Related errors
- sync hub push: acked[${index}] must be an object
- sync hub push: malformed acked[${index}]
- sync hub push: duplicate operation tuple claimed different s
- sync hub push: distinct operation tuples claimed the same se
- sync hub push: 200 response acknowledgment multiplicity mism
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/1a91cf808b2539ba.
Report an issue: GitHub.