affaan-m/ECC · error · Error
Canonical session snapshot requires workers
Error message
Canonical session snapshot requires workers[${index}].runtime to be an object What it means
validateCanonicalSnapshot throws this when a worker entry in the snapshot is missing a runtime object (or runtime is not a plain object). The canonical schema requires workers[i].runtime to carry kind (string), command (optional string), and the booleans active and dead, so renderer code can branch on process liveness without defensive checks.
Solutions
- Add a runtime object { kind, command?, active, dead } to the worker at the reported index.
- Update the producing adapter to populate runtime for every worker.
- Regenerate the snapshot with the current normalize*Session adapters so the runtime block is filled in.
- Run validateCanonicalSnapshot on newly built snapshots in tests to catch missing runtime early.
Example fix
// before
worker.runtime = null;
// after
worker.runtime = { kind: 'claude', command: 'claude --resume', active: true, dead: false }; Defensive patterns
Strategy: validation
Validate before calling
const runtimeOk = snapshot.workers.every(w => w && typeof w.runtime === 'object' && w.runtime !== null && typeof w.runtime.kind === 'string' && typeof w.runtime.active === 'boolean' && typeof w.runtime.dead === 'boolean');
if (!runtimeOk) throw new Error('every worker needs a runtime { kind, active, dead }'); Type guard
function hasRuntime(w) { return !!w && typeof w.runtime === 'object' && w.runtime !== null && !Array.isArray(w.runtime); } Try / catch
try { persistCanonicalSnapshot(snapshot); } catch (err) { if (String(err.message).includes('.runtime to be an object')) { console.error('Worker missing runtime block:', err.message); /* patch runtime and retry */ } else { throw err; } } Prevention
- Initialize runtime at worker creation: { kind, command: undefined, active: false, dead: false }.
- Keep adapters in sync with the canonical schema; bump versions together.
- Include snapshot fixtures in unit tests validated by validateCanonicalSnapshot.
- Never hand-write snapshot JSON; use builder helpers.
When it happens
Trigger: Passing a snapshot whose worker omits the runtime field entirely, sets runtime to null, or assigns a string/array instead of an object; older adapters that predate the runtime block.
Common situations: Schema drift between a session-recording tool that emits flat workers and the current canonical-session validator; manually constructing test snapshots without the runtime block; loading snapshots persisted by an older plugin version.
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 aggregates.healths to…
- Canonical session snapshot requires aggregates.states to be…
- Canonical session snapshot requires aggregates to be an…
- Canonical session snapshot requires aggregates.workerCount…
- Canonical session snapshot requires workers
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/c54b1bf5f75c4f4e.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/session-adapters/canonical-session.js:207
if (!Array.isArray(snapshot.workers)) {
throw new Error('Canonical session snapshot requires workers to be an array');
}
snapshot.workers.forEach((worker, index) => {
if (!isObject(worker)) {
throw new Error(`Canonical session snapshot requires workers[${index}] to be an object`);
}
ensureString(worker.id, `workers[${index}].id`);
ensureString(worker.label, `workers[${index}].label`);
ensureString(worker.state, `workers[${index}].state`);
ensureString(worker.health, `workers[${index}].health`);
ensureOptionalString(worker.branch, `workers[${index}].branch`);
ensureOptionalString(worker.worktree, `workers[${index}].worktree`);
if (!isObject(worker.runtime)) {
throw new Error(`Canonical session snapshot requires workers[${index}].runtime to be an object`);
}
ensureString(worker.runtime.kind, `workers[${index}].runtime.kind`);
ensureOptionalString(worker.runtime.command, `workers[${index}].runtime.command`);
ensureBoolean(worker.runtime.active, `workers[${index}].runtime.active`);
ensureBoolean(worker.runtime.dead, `workers[${index}].runtime.dead`);
if (!isObject(worker.intent)) {
throw new Error(`Canonical session snapshot requires workers[${index}].intent to be an object`);
}
ensureStringAllowEmpty(worker.intent.objective, `workers[${index}].intent.objective`);
ensureArrayOfStrings(worker.intent.seedPaths, `workers[${index}].intent.seedPaths`);
if (!isObject(worker.outputs)) {
throw new Error(`Canonical session snapshot requires workers[${index}].outputs to be an object`);
}
View on GitHub (pinned to 8321021c54)