affaan-m/ECC · error · Error

Canonical session snapshot must be an object

Error message

Canonical session snapshot must be an object

What it means

Thrown at the top of validateCanonicalSnapshot when the snapshot argument is not a plain object (is null, an array, a primitive, or undefined). This is the outermost shape guard before any field validation runs.

Source

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

  const failedCount = (workerStates.failed || 0) + (workerStates.error || 0);
  if (failedCount > 0) {
    return 'failed';
  }

  const completedCount = (workerStates.completed || 0)
    + (workerStates.succeeded || 0)
    + (workerStates.success || 0)
    + (workerStates.done || 0);
  if (completedCount === totalWorkers) {
    return 'completed';
  }

  return 'idle';
}

function validateCanonicalSnapshot(snapshot) {
  if (!isObject(snapshot)) {
    throw new Error('Canonical session snapshot must be an object');
  }

  ensureString(snapshot.schemaVersion, 'schemaVersion');
  if (snapshot.schemaVersion !== SESSION_SCHEMA_VERSION) {
    throw new Error(`Unsupported canonical session schema version: ${snapshot.schemaVersion}`);
  }

  ensureString(snapshot.adapterId, 'adapterId');

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

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Confirm the snapshot is a single object before validating.
  2. If loading from a file, check the parsed value is an object (not array) before use.
  3. Loop over arrays of snapshots individually rather than passing the array.

Example fix

// before
validateCanonicalSnapshot(JSON.parse(raw)); // raw parses to an array

// after
const parsed = JSON.parse(raw);
const snapshot = Array.isArray(parsed) ? parsed[0] : parsed;
if (!snapshot || typeof snapshot !== 'object') throw new Error('No snapshot');
validateCanonicalSnapshot(snapshot);
Defensive patterns

Strategy: type-guard

Validate before calling

const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
  throw new Error('Snapshot must be a single object');
}
validateCanonicalSnapshot(parsed);

Type guard

function isPlainObject(v) {
  return Boolean(v) && typeof v === 'object' && !Array.isArray(v);
}

Prevention

When it happens

Trigger: Calling validateCanonicalSnapshot(null), validateCanonicalSnapshot([]), validateCanonicalSnapshot('string'), validateCanonicalSnapshot(undefined), or passing a JSON.parse result that is an array at the top level.

Common situations: A recorded snapshot file whose top-level JSON is an array instead of an object; a code path that passes a list of snapshots instead of one; a deserialization that returned null; a refactor that passes the wrong variable.

Related errors


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