thedotmack/claude-mem · critical
cloud sync ack conflict for ${body.id} rev ${body.entity_rev
Error message
cloud sync ack conflict for ${body.id} rev ${body.entity_rev} What it means
Thrown in advanceEntityHead during stampAcked when an entity already has a row in sync_entity_heads with the SAME entity_rev but a DIFFERENT operation_sha256. entity_rev is meant to be content-addressed: the same rev for the same entity must hash to the same operation. A divergence means two distinct operations claim the same revision — a genuine content conflict or a hash collision.
Source
Thrown at src/services/sync/CloudSync.ts:1137
this.reconcileAckedContent(body, pushedOp.operationSha256, now);
}
});
tx();
}
private advanceEntityHead(
body: ReturnType<typeof parseCanonicalOperation>,
operationSha256: string,
now: number,
): void {
const current = this.db.prepare(`
SELECT entity_rev, operation_sha256 FROM sync_entity_heads WHERE entity_id = ?
`).get(body.id) as { entity_rev: string; operation_sha256: string } | undefined;
if (current) {
const order = compareCanonicalDecimals(body.entity_rev, current.entity_rev);
if (order < 0) return;
if (order === 0 && current.operation_sha256 !== operationSha256) {
throw new Error(`cloud sync ack conflict for ${body.id} rev ${body.entity_rev}`);
}
}
this.db.prepare(`
INSERT INTO sync_entity_heads
(entity_id, kind, origin_device_id, origin_local_id, entity_rev,
operation_sha256, deleted, updated_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(entity_id) DO UPDATE SET
entity_rev=excluded.entity_rev,
operation_sha256=excluded.operation_sha256,
deleted=excluded.deleted,
updated_at_epoch=excluded.updated_at_epoch
`).run(
body.id, body.kind, body.origin_device_id, body.origin_local_id,
body.entity_rev, operationSha256, body.deleted ? 1 : 0, now,
);
}
View on GitHub (pinned to d768ba3643)
Solutions
- Inspect sync_entity_heads for body.id: compare stored operation_sha256 vs the acked operation_sha256 — a real divergence shows two different ops at one rev.
- If the hashes differ due to encoding/casing normalization, fix the producer to emit canonical operation_sha256 consistently.
- If it is genuine divergence, resolve manually (pick the authoritative op, bump entity_rev) — do not let stampAcked silently overwrite.
- Run remap-outbox or a reseed to reconcile divergent entity heads after deciding the canonical op.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before pushing, confirm local entity heads agree with the op hashes you push:
function checkHeadConsistency(db: Database, id: string, entityRev: string, opSha: string): void {
const row = db.prepare('SELECT operation_sha256 FROM sync_entity_heads WHERE entity_id=?').get(id) as { operation_sha256?: string } | undefined;
if (row && compareCanonicalDecimals(entityRev, /* current rev */ row.operation_sha256) === 0
&& row.operation_sha256 !== opSha) {
throw new Error('pre-push: head hash divergence for ' + id);
}
} Try / catch
try { await cloudSync.push(pushed); }
catch (e) {
if (e instanceof Error && e.message.startsWith('cloud sync ack conflict for')) {
// content-addressed divergence — needs human resolution, do not auto-overwrite
logger.error('SYNC', e.message); await alertOperator(e.message); return;
}
throw e;
} Prevention
- Produce operation_sha256 from canonical-encoded payloads so the same rev always hashes identically.
- Never let two devices claim the same entity_rev for different content; coordinate rev allocation via the hub.
- Run remap-outbox after schema/migration changes to keep entity heads consistent.
When it happens
Trigger: stampAcked -> advanceEntityHead: SELECT finds an existing head with current.entity_rev === body.entity_rev but current.operation_sha256 !== operationSha256. compareCanonicalDecimals returns 0 (equal rev) but the hashes differ, so it throws rather than silently overwriting.
Common situations: Two devices produced different operation content that hashed differently but were assigned the same entity_rev by the hub, an operation_sha256 recomputed differently between push and ack (encoding/casing), or a real hash collision (astronomically rare). Can also follow a partial/buggy remap of the outbox. Indicates data divergence that must be investigated, not auto-resolved.
Related errors
- sync hub push: acked[${index}] must be an object
- sync hub push: malformed acked[${index}]
- sync hub push: 200 response contains an extra or mismatched
- sync hub push: duplicate operation tuple claimed different s
- sync hub push: distinct operation tuples claimed the same se
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/ecd59123cbb04776.
Report an issue: GitHub.