thedotmack/claude-mem · error
sync hub push: duplicate operation tuple claimed different…
Error message
sync hub push: duplicate operation tuple claimed different sequences
What it means
The same (id, kind, entity_rev, operation_sha256) tuple appears more than once in the acked array but each occurrence claims a different seq — the hub assigned two different log positions to one operation. A tuple maps to exactly one sequence by construction. Caught in validatePushResponse before stamping; flush() backs off and retries. Persistent occurrences point to a hub append/dedupe bug (e.g. the (origin_device, kind, origin_id, rev) dedupe failing under retries).
Solutions
- Reproduce with a duplicate POST of the same op body and inspect how many acks/seqs the hub returns
- On the hub, make the (origin_device, kind, origin_id, rev) dedupe atomic with the append (unique constraint or transactional check)
- If duplicate log entries already exist, compact/repair the hub log before clients can converge
- Until fixed, expect the client to safely reject and retry — no local corruption occurs
Defensive patterns
Strategy: try-catch
Try / catch
if (/duplicate operation tuple claimed different sequences/.test(sync.status().lastError ?? '')) {
// hub assigned two log positions to one op: test duplicate POST idempotency
// against the hub, fix its dedupe, then let client retries converge
} Prevention
- Give the hub an atomic unique constraint on (origin_device, kind, origin_id, rev) covering appends
- Load-test the hub with duplicate concurrent submissions of the same op
- Treat any occurrence as a hub bug — the client can only safely reject and retry
When it happens
Trigger: Client retries a timed-out POST and the hub appends twice because its dedupe key is broken, then acks both positions; a hub race between duplicate submit handlers; replica divergence merging the same op at two seqs.
Common situations: Hub dedupe index missing/partial after a schema migration; retry storms during network flaps exposing a hub race; multi-region hub with non-atomic log merge.
Related errors
- sync hub push: 200 response acknowledgment multiplicity…
- sync hub push: 200 response contains an extra or mismatched…
- sync hub push: acknowledgment seq exceeds head_seq
- sync hub push: checkpoint order requires head_seq <=…
- sync hub push: distinct operation tuples claimed the same…
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/77fd47a699efdd7a.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/CloudSync.ts:1045
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;
if (actual !== expected) {
throw new Error(
`sync hub push: 200 response acknowledgment multiplicity mismatch (expected ${expected}, received ${actual})`
);
}
}View on GitHub (pinned to e2d1df569a)