thedotmack/claude-mem · error
cloud sync canonical payload: ${name} is not valid JSON
Error message
cloud sync canonical payload: ${name} is not valid JSON What it means
The column is stored as text, but JSON.parse rejects it — the stored value is truncated or otherwise not valid JSON (a crash mid-write, mangled quotes, or plain prose in a JSON column). The push halts at this row so the corrupt payload never reaches the hub; the message names the offending column.
Source
Thrown at src/services/sync/CloudSync.ts:164
function decimalPayload(value: unknown, name: string, nullable = false): string | null {
if (value === null || value === undefined) {
if (nullable) return null;
return '0';
}
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
throw new Error(`cloud sync canonical payload: ${name} must be a non-negative safe integer`);
}
return String(value);
}
function jsonPayloadColumn(value: unknown, name: string, expected: 'array' | 'object'): unknown {
if (value === null || value === undefined) return null;
if (typeof value !== 'string') {
throw new Error(`cloud sync canonical payload: ${name} must be stored JSON text`);
}
let parsed: unknown;
try { parsed = JSON.parse(value); } catch {
throw new Error(`cloud sync canonical payload: ${name} is not valid JSON`);
}
if (expected === 'array' && !Array.isArray(parsed)) {
throw new Error(`cloud sync canonical payload: ${name} must decode to an array`);
}
if (expected === 'object' && (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))) {
throw new Error(`cloud sync canonical payload: ${name} must decode to an object`);
}
return parsed;
}
const KINDS: KindSpec[] = [
{
kind: 'observation',
localTable: 'observations',
selectSql: `
SELECT CAST(id AS TEXT) AS id, CAST(sync_rev AS TEXT) AS sync_rev,
memory_session_id, project, text, type, title, subtitle,
facts, narrative, concepts, files_read, files_modified, prompt_number,View on GitHub (pinned to e2d1df569a)
Solutions
- Find the invalid rows with SQLite's own validator: SELECT id FROM <table> WHERE <col> IS NOT NULL AND json_valid(<col>) = 0
- Repair or null them out per semantics: UPDATE <table> SET <col> = '[]' WHERE <col> IS NOT NULL AND json_valid(<col>) = 0 (use NULL if the column is nullable/optional)
- Re-run the sync push
- Investigate what wrote the bad value — a recurring truncation pattern points to a crash loop or hot-copy backup
Example fix
-- before SELECT id, facts FROM observations WHERE facts IS NOT NULL AND json_valid(facts) = 0; -- after UPDATE observations SET facts = '[]' WHERE facts IS NOT NULL AND json_valid(facts) = 0;
Defensive patterns
Strategy: validation
Validate before calling
-- Pre-sync check: stored JSON actually parses
SELECT COUNT(*) AS bad FROM observations
WHERE (facts IS NOT NULL AND json_valid(facts) = 0)
OR (concepts IS NOT NULL AND json_valid(concepts) = 0)
OR (metadata IS NOT NULL AND json_valid(metadata) = 0);
-- bad = 0 before enabling cloud sync Type guard
const isParsableJsonText = (v: unknown): v is string =>
typeof v === 'string' && (() => { try { JSON.parse(v); return true; } catch { return false; } })(); Try / catch
try {
await cloudSync.push();
} catch (e) {
if (e instanceof Error && e.message.includes('is not valid JSON')) {
// repair with UPDATE ... SET col = '[]' WHERE json_valid(col) = 0, then re-push
} else throw e;
} Prevention
- Never hot-copy the SQLite file while writers are active — use the backup API or checkpoint first
- Add json_valid() assertions in test fixtures and seed data
- Avoid sed/regex edits on serialized JSON columns
- Investigate crash loops if truncation recurs
When it happens
Trigger: Power loss or crash during the UPDATE that wrote the column leaving truncated text; the SQLite file copied while hot; sed/regex edits mangling escaped quotes; a writer appending to the column instead of replacing it.
Common situations: Unclean shutdown during heavy writes; DB restored from a partial backup; manual data surgery on the file; encoding conversion tools corrupting escape sequences.
Related errors
- cloud sync canonical payload: ${name} must decode to an arra
- sync hub status: response must be an object
- 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} must decode to an obje
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/1148f14734eb3193.
Report an issue: GitHub.