affaan-m/ECC · error · Error
Canonical session snapshot requires workers
Error message
Canonical session snapshot requires workers[${index}] to be an object What it means
This error is thrown by validateCanonicalSnapshot in scripts/lib/session-adapters/canonical-session.js when a canonical session snapshot's workers array contains a non-object entry. The validator walks every element of snapshot.workers and enforces the canonical snapshot schema before the snapshot is persisted or normalized. It guarantees downstream consumers can safely read worker.id, label, state, and health.
Solutions
- Inspect the snapshot's workers array at the reported index and replace the non-object entry with a full worker object containing id, label, state, health, runtime, intent, outputs, and artifacts.
- Fix the upstream adapter or builder that produced the workers array so every entry is a plain object.
- Validate the snapshot with validateCanonicalSnapshot (or a schema tool) immediately after construction to catch malformed workers before persisting.
- If the snapshot came from a file, re-generate it with the current session-manager version rather than patching stale JSON.
Example fix
// before
const snapshot = { workers: ['worker-a'] };
persistCanonicalSnapshot(snapshot);
// after
const snapshot = {
workers: [{ id: 'worker-a', label: 'Worker A', state: 'idle', health: 'healthy',
runtime: { kind: 'dmux', active: true, dead: false },
intent: { objective: '', seedPaths: [] },
outputs: { summary: [], validation: [], remainingRisks: [] },
artifacts: {} }]
};
persistCanonicalSnapshot(snapshot); Defensive patterns
Strategy: validation
Validate before calling
function isValidWorker(w) { return !!w && typeof w === 'object' && !Array.isArray(w); }
if (!Array.isArray(snapshot.workers) || !snapshot.workers.every(isValidWorker)) throw new Error('snapshot.workers must be an array of objects'); Type guard
function isWorkerObject(w) { return typeof w === 'object' && w !== null && !Array.isArray(w) && typeof w.id === 'string' && typeof w.label === 'string' && typeof w.state === 'string' && typeof w.health === 'string'; } Try / catch
try { persistCanonicalSnapshot(snapshot); } catch (err) { if (String(err.message).includes('workers[')) { console.error('Malformed worker entry in snapshot:', err.message); /* rebuild or regenerate snapshot */ } else { throw err; } } Prevention
- Always build workers via a factory that returns the full worker shape (id, label, state, health, runtime, intent, outputs, artifacts).
- Never use delete on elements of the workers array; use filter().
- Validate snapshots with validateCanonicalSnapshot immediately after construction.
- Schema-check any externally sourced snapshot JSON before passing it in.
When it happens
Trigger: Calling persistCanonicalSnapshot or any of the normalize*Session/normalizeDmuxSnapshot adapters with a snapshot whose workers array contains null, undefined, a primitive, or an array element instead of a worker object.
Common situations: Adapters built from stale schemas that still emit string or null worker entries; hand-edited or externally generated snapshot JSON loaded and passed to persistCanonicalSnapshot; a mapping step that filters workers but leaves sparse array holes (delete on array elements).
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/c3eaf1c7886760d0.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/session-adapters/canonical-session.js:196
ensureString(snapshot.session.id, 'session.id');
ensureString(snapshot.session.kind, 'session.kind');
ensureString(snapshot.session.state, 'session.state');
ensureOptionalString(snapshot.session.repoRoot, 'session.repoRoot');
if (!isObject(snapshot.session.sourceTarget)) {
throw new Error('Canonical session snapshot requires session.sourceTarget to be an object');
}
ensureString(snapshot.session.sourceTarget.type, 'session.sourceTarget.type');
ensureString(snapshot.session.sourceTarget.value, 'session.sourceTarget.value');
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`);
View on GitHub (pinned to 8321021c54)