thedotmack/claude-mem · error
cloud sync canonical payload: ${name} must decode to an arra
Error message
cloud sync canonical payload: ${name} must decode to an array What it means
The column parsed as JSON successfully, but the decoded value is not an array even though the kind's op-body contract (facts, concepts, files_read, files_modified) requires one — for example '{}' or '"text"' stored in files_read. Canonicalization aborts with the column name so the hub never receives a shape-varying field.
Source
Thrown at src/services/sync/CloudSync.ts:167
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,
discovery_tokens, content_hash, generated_by_model, agent_type, agent_id,
metadata, merged_into_project, created_at, created_at_epoch
FROM observationsView on GitHub (pinned to e2d1df569a)
Solutions
- Find shape mismatches: SELECT id FROM <table> WHERE <col> IS NOT NULL AND json_type(<col>) <> 'array'
- Convert offenders — wrap single values, drop maps to values, or reset to '[]': UPDATE <table> SET <col> = '[]' WHERE json_type(<col>) <> 'array'
- Re-run the sync push
- Fix the writer to always serialize these fields as arrays
Example fix
-- before SELECT id FROM observations WHERE concepts IS NOT NULL AND json_type(concepts) <> 'array'; -- after UPDATE observations SET concepts = '[]' WHERE concepts IS NOT NULL AND json_type(concepts) <> 'array';
Defensive patterns
Strategy: validation
Validate before calling
-- Pre-sync check: array-contract columns decode to arrays
SELECT COUNT(*) AS bad FROM observations
WHERE (facts IS NOT NULL AND json_type(facts) <> 'array')
OR (files_read IS NOT NULL AND json_type(files_read) <> 'array');
-- bad = 0 before enabling cloud sync Type guard
const decodesToArray = (v: unknown): v is string =>
typeof v === 'string' && (() => { try { return Array.isArray(JSON.parse(v)); } catch { return false; } })(); Try / catch
try {
await cloudSync.push();
} catch (e) {
if (e instanceof Error && e.message.includes('must decode to an array')) {
// normalize the named column to '[]' (or a real array), then re-push
} else throw e;
} Prevention
- Pin one array shape for these fields across all writer versions
- Add json_type() assertions to migrations between writer generations
- Validate imported data with json_type() before it lands
- Keep fixture/seed data shape-checked in CI
When it happens
Trigger: An older writer version stored objects or plain strings in these columns; a merge/migration path wrote a dict keyed by id instead of a list; a default value changed shape between versions.
Common situations: Upgrades between writer generations with different array conventions; imports from tools that emit key-maps; hand-written seed data using objects for brevity.
Related errors
- cloud sync canonical payload: ${name} must decode to an obje
- 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
- sync hub status: response is not JSON
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/9b42e435dbd47489.
Report an issue: GitHub.