affaan-m/ECC · error
Canonical session snapshot must be an object
Error message
Canonical session snapshot must be an object
What it means
validateCanonicalSnapshot is the entry gate for every snapshot write/normalize path (persistCanonicalSnapshot, getFallbackSessionRecordingPath, normalizeDmuxSnapshot, normalizeClaudeHistorySession, normalizeCodexWorktreeSession, normalizeOpencodeSession). This top-of-function check throws when the value passed is not a plain object — null, undefined, an array, a string, or a number. The library treats the snapshot as a structured record and refuses anything else.
Solutions
- JSON.parse file/string contents before calling the persist/normalize function
- Check the argument is non-null before calling: if (!snapshot) throw/handle upstream
- Verify you are calling the normalize* adapter with the correct argument order
- Add a null/undefined guard in the caller that produces the snapshot
Example fix
// before persistCanonicalSnapshot(fs.readFileSync(path, 'utf8')); // after persistCanonicalSnapshot(JSON.parse(fs.readFileSync(path, 'utf8')));
Defensive patterns
Strategy: type-guard
Validate before calling
if (!isSnapshotObject(input)) throw new TypeError('Expected snapshot object'); Type guard
const isSnapshotObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
Try / catch
try { persistCanonicalSnapshot(snap); } catch (e) { if (e.message === 'Canonical session snapshot must be an object') { /* log and regenerate */ } else throw e; } Prevention
- Parse JSON before calling
- Check producer return values for undefined
When it happens
Trigger: Passing null/undefined to persistCanonicalSnapshot; passing a JSON string of the snapshot instead of the parsed object; an upstream function returning undefined on error and its result being forwarded directly; spreading an array where an object was expected.
Common situations: Reading a snapshot file that failed to parse and forwarding null; a normalize adapter called with the wrong argument order so the snapshot argument is undefined; forgetting JSON.parse on file contents.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Canonical session snapshot requires
- Canonical session snapshot requires
- Canonical session snapshot requires
- Invalid managed hook handler at
- spec.schedule must be an array of six-cell rows
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/c57fa26dae80a1de.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/session-adapters/canonical-session.js:164
const failedCount = (workerStates.failed || 0) + (workerStates.error || 0);
if (failedCount > 0) {
return 'failed';
}
const completedCount = (workerStates.completed || 0)
+ (workerStates.succeeded || 0)
+ (workerStates.success || 0)
+ (workerStates.done || 0);
if (completedCount === totalWorkers) {
return 'completed';
}
return 'idle';
}
function validateCanonicalSnapshot(snapshot) {
if (!isObject(snapshot)) {
throw new Error('Canonical session snapshot must be an object');
}
ensureString(snapshot.schemaVersion, 'schemaVersion');
if (snapshot.schemaVersion !== SESSION_SCHEMA_VERSION) {
throw new Error(`Unsupported canonical session schema version: ${snapshot.schemaVersion}`);
}
ensureString(snapshot.adapterId, 'adapterId');
if (!isObject(snapshot.session)) {
throw new Error('Canonical session snapshot requires session to be an object');
}
ensureString(snapshot.session.id, 'session.id');
ensureString(snapshot.session.kind, 'session.kind');
ensureString(snapshot.session.state, 'session.state');
ensureOptionalString(snapshot.session.repoRoot, 'session.repoRoot');
View on GitHub (pinned to 8321021c54)