thedotmack/claude-mem · warning
cloud sync identity unavailable; refusing an unreplicated de
Error message
cloud sync identity unavailable; refusing an unreplicated delete
What it means
HTTP 503 returned by the DataRoutes delete handler when cloud sync IS configured but has no deviceId yet — the device identity that tags replicated mutations has not been established. Deleting a local-origin row without that identity would emit a delete other replicas could not attribute, so the worker refuses and asks the client to retry later.
Source
Thrown at src/services/worker/http/routes/DataRoutes.ts:361
this.badRequest(res, 'id must be a positive canonical decimal string');
return;
}
const store = this.dbManager.getSessionStore();
const row = store.db.prepare(`
SELECT CAST(id AS TEXT) AS id FROM ${table}
WHERE id = ? AND origin_device_id IS NULL
`).get(originLocalId) as { id: string } | undefined;
if (!row) {
this.notFound(res, `${kind} #${originLocalId} not found`);
return;
}
const cloudSync = this.dbManager.getCloudSync();
let entityRev: string | null = null;
if (cloudSync?.isConfigured()) {
if (!cloudSync.status().deviceId) {
res.status(503).json({ error: 'cloud sync identity unavailable; refusing an unreplicated delete' });
return;
}
entityRev = cloudSync.queueDelete(kind, originLocalId);
} else {
// A row with an acknowledged entity head must never be silently deleted
// while its sync identity is unavailable: that would strand replicas.
const acknowledged = store.db.prepare(`
SELECT 1 AS found FROM sync_entity_heads
WHERE kind = ? AND origin_local_id = ? LIMIT 1
`).get(kind, originLocalId) as { found: number } | undefined;
if (acknowledged) {
res.status(503).json({ error: 'cloud sync unavailable; refusing an unreplicated delete' });
return;
}
store.db.prepare(
`DELETE FROM ${table} WHERE id = ? AND origin_device_id IS NULL`
).run(originLocalId);
}View on GitHub (pinned to 8bc631a71a)
Solutions
- Retry the delete after the first successful sync run establishes the deviceId
- Check sync status (cloudSync.status()) — if deviceId stays null, inspect sync credentials/connectivity
- If sync was enabled by mistake, disable cloud sync so the delete takes the local-only path
Example fix
// before
await fetch(`${base}/api/data/session/${id}`, { method: 'DELETE' }); // 503 identity unavailable
// after
await waitForSyncIdentity(); // poll status endpoint until deviceId present
await fetch(`${base}/api/data/session/${id}`, { method: 'DELETE' }); Defensive patterns
Strategy: retry
Validate before calling
async function syncIdentityReady(base: string): Promise<boolean> {
// before deleting replicated data, confirm the device identity exists
const s = await (await fetch(`${base}/api/settings`)).json();
return Boolean(s.cloudSync?.deviceId);
} Type guard
function isSyncIdentityUnavailable(body: unknown, status: number): boolean {
return status === 503 && typeof body === 'object' && body !== null &&
String((body as { error?: string }).error).includes('identity unavailable');
} Try / catch
for (let i = 0; i < 5; i++) {
const res = await del(`${base}/api/data/${kind}/${id}`);
if (res.status !== 503) return handle(res);
await sleep(2000); // first sync exchange provisions deviceId
}
throw new Error('sync identity never became available'); Prevention
- After enabling cloud sync, wait for the first successful sync before issuing deletes
- Monitor cloudSync.status().deviceId and alert when it stays null with sync configured
- Automate testing of the delete path only on post-first-sync states
When it happens
Trigger: DELETE on a local-origin session/observation immediately after configuring cloud sync, before the first successful sync exchange provisions the device identity; or after an identity reset where status().deviceId is null again.
Common situations: Fresh installs where sync credentials were entered but the initial handshake failed (network down, bad endpoint); race between the settings API enabling sync and the sync engine registering; wiping local identity state under ~/.claude-mem.
Related errors
- cloud sync unavailable; refusing an unreplicated delete
- cloud sync canonical payload: ${name} must be a non-negative
- cloud sync canonical payload: ${name} must be stored JSON te
- cloud sync canonical payload: ${name} is not valid JSON
- cloud sync canonical payload: ${name} must decode to an arra
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20).
Data as JSON: /api/errors/71f577c2f556a7b4.
Report an issue: GitHub.