{"record":{"id":"c3eaf1c7886760d0","repo":"affaan-m/ECC","slug":"canonical-session-snapshot-requires-workers-inde","errorCode":null,"errorMessage":"Canonical session snapshot requires workers[${index}] to be an object","messagePattern":"Canonical session snapshot requires workers\\[(.+?)\\] to be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/session-adapters/canonical-session.js","lineNumber":196,"sourceCode":"  ensureString(snapshot.session.id, 'session.id');\n  ensureString(snapshot.session.kind, 'session.kind');\n  ensureString(snapshot.session.state, 'session.state');\n  ensureOptionalString(snapshot.session.repoRoot, 'session.repoRoot');\n\n  if (!isObject(snapshot.session.sourceTarget)) {\n    throw new Error('Canonical session snapshot requires session.sourceTarget to be an object');\n  }\n\n  ensureString(snapshot.session.sourceTarget.type, 'session.sourceTarget.type');\n  ensureString(snapshot.session.sourceTarget.value, 'session.sourceTarget.value');\n\n  if (!Array.isArray(snapshot.workers)) {\n    throw new Error('Canonical session snapshot requires workers to be an array');\n  }\n\n  snapshot.workers.forEach((worker, index) => {\n    if (!isObject(worker)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}] to be an object`);\n    }\n\n    ensureString(worker.id, `workers[${index}].id`);\n    ensureString(worker.label, `workers[${index}].label`);\n    ensureString(worker.state, `workers[${index}].state`);\n    ensureString(worker.health, `workers[${index}].health`);\n    ensureOptionalString(worker.branch, `workers[${index}].branch`);\n    ensureOptionalString(worker.worktree, `workers[${index}].worktree`);\n\n    if (!isObject(worker.runtime)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}].runtime to be an object`);\n    }\n\n    ensureString(worker.runtime.kind, `workers[${index}].runtime.kind`);\n    ensureOptionalString(worker.runtime.command, `workers[${index}].runtime.command`);\n    ensureBoolean(worker.runtime.active, `workers[${index}].runtime.active`);\n    ensureBoolean(worker.runtime.dead, `workers[${index}].runtime.dead`);\n","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/session-adapters/canonical-session.js#L178-L214","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nconst snapshot = { workers: ['worker-a'] };\npersistCanonicalSnapshot(snapshot);\n// after\nconst snapshot = {\n  workers: [{ id: 'worker-a', label: 'Worker A', state: 'idle', health: 'healthy',\n    runtime: { kind: 'dmux', active: true, dead: false },\n    intent: { objective: '', seedPaths: [] },\n    outputs: { summary: [], validation: [], remainingRisks: [] },\n    artifacts: {} }]\n};\npersistCanonicalSnapshot(snapshot);","handlingStrategy":"validation","validationCode":"function isValidWorker(w) { return !!w && typeof w === 'object' && !Array.isArray(w); }\nif (!Array.isArray(snapshot.workers) || !snapshot.workers.every(isValidWorker)) throw new Error('snapshot.workers must be an array of objects');","typeGuard":"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'; }","tryCatchPattern":"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; } }","preventionTips":["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."],"tags":["schema-validation","session-snapshot"],"backgroundTag":"schema-validation-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}