affaan-m/ECC · error · Error

Canonical session snapshot requires ${fieldPath} to be a str

Error message

Canonical session snapshot requires ${fieldPath} to be a string or null

What it means

Thrown by the ensureOptionalString helper when a field that may be null/undefined or a string is instead some other type. Applied to session.repoRoot, workers[i].branch, workers[i].worktree, and workers[i].runtime.command — these are optional but, when present, must be strings.

Source

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

    .map(line => line.trim())
    .filter(Boolean);
}

function ensureString(value, fieldPath) {
  if (typeof value !== 'string' || value.length === 0) {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be a non-empty string`);
  }
}

function ensureStringAllowEmpty(value, fieldPath) {
  if (typeof value !== 'string') {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be a string`);
  }
}

function ensureOptionalString(value, fieldPath) {
  if (value !== null && value !== undefined && typeof value !== 'string') {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be a string or null`);
  }
}

function ensureBoolean(value, fieldPath) {
  if (typeof value !== 'boolean') {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be a boolean`);
  }
}

function ensureArrayOfStrings(value, fieldPath) {
  if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be an array of strings`);
  }
}

function ensureInteger(value, fieldPath) {
  if (!Number.isInteger(value) || value < 0) {
    throw new Error(`Canonical session snapshot requires ${fieldPath} to be a non-negative integer`);

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Normalize optional fields to either a string or null before building the snapshot.
  2. Use a helper: const optStr = v => (typeof v === 'string' ? v : v == null ? null : String(v)).
  3. Drop fields you cannot confidently type as string|null.

Example fix

// before
session: { repoRoot: metadata.worktree, ... } // worktree is an object

// after
const toOptStr = v => (typeof v === 'string' ? v : null);
session: { repoRoot: toOptStr(metadata.worktree), ... }
Defensive patterns

Strategy: type-guard

Validate before calling

const optStr = v => (typeof v === 'string' ? v : null);
// apply to repoRoot, branch, worktree, runtime.command

Type guard

function isOptionalString(v) {
  return v === null || v === undefined || typeof v === 'string';
}

Prevention

When it happens

Trigger: A worker.branch set to a number or boolean; session.repoRoot set to an object; runtime.command set to null incorrectly typed as something else. Typically an adapter forwards a source field that exists but is not a string.

Common situations: A source session record where branch is a numeric id; a transform that wraps repoRoot in an object; mixed data from an adapter whose source schema differs from the canonical one.

Related errors


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