affaan-m/ECC · error · Error

Canonical session snapshot requires workers to be an array

Error message

Canonical session snapshot requires workers to be an array

What it means

Thrown by validateCanonicalSnapshot when snapshot.workers is not an array. Workers is the list of agent runtimes in the session; even a session with no workers must supply an empty array so aggregates and state derivation have a defined input.

Source

Thrown at scripts/lib/session-adapters/canonical-session.js:191

  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');

  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`);
    }

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Always assign an array (possibly empty) to workers.
  2. Use buildAggregates(workers) alongside it so counts stay consistent.
  3. Wrap single workers in an array literal when constructing.

Example fix

// before
validateCanonicalSnapshot({ ..., workers: singleWorker, aggregates: { workerCount: 1 } });

// after
validateCanonicalSnapshot({ ..., workers: [singleWorker], aggregates: buildAggregates([singleWorker]) });
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Array.isArray(snapshot.workers)) {
  throw new Error('snapshot.workers must be an array');
}

Type guard

function hasWorkersArray(s) {
  return s && typeof s === 'object' && Array.isArray(s.workers);
}

Prevention

When it happens

Trigger: A snapshot where workers is null, undefined, an object, or a single worker object instead of an array. Happens when an adapter assigns a single worker without wrapping it in [], or omits the key entirely.

Common situations: A normalize function assigning worker instead of [worker]; a hand-built snapshot that forgets the workers key; a transform that converts workers to an object keyed by id.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/01134c22ae10f33e. Report an issue: GitHub.