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

  1. 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.
  2. If the hashes differ due to encoding/casing normalization, fix the producer to emit canonical operation_sha256 consistently.
  3. If it is genuine divergence, resolve manually (pick the authoritative op, bump entity_rev) — do not let stampAcked silently overwrite.
  4. 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

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


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