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

  1. Add a runtime object { kind, command?, active, dead } to the worker at the reported index.
  2. Update the producing adapter to populate runtime for every worker.
  3. Regenerate the snapshot with the current normalize*Session adapters so the runtime block is filled in.
  4. 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

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


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)