affaan-m/ECC · error

Failed to serialize ${label}: ${error.message}

Error message

Failed to serialize ${label}: ${error.message}

What it means

Thrown by stringifyJson() in the state-store queries module when JSON.stringify fails on a value the caller asked to write into a JSON column. The try/catch wraps the native call so the surfaced error names the column label rather than reporting a bare 'Converting circular structure to JSON'. The helper is used to serialize snapshots and other structured fields before they go into SQLite.

Source

Thrown at scripts/lib/state-store/queries.js:36

    throw new Error(`Invalid limit: ${value}`);
  }

  return parsed;
}

function parseJsonColumn(value, fallback) {
  if (value === null || value === undefined || value === '') {
    return fallback;
  }

  return JSON.parse(value);
}

function stringifyJson(value, label) {
  try {
    return JSON.stringify(value);
  } catch (error) {
    throw new Error(`Failed to serialize ${label}: ${error.message}`);
  }
}

function mapSessionRow(row) {
  const snapshot = parseJsonColumn(row.snapshot, {});
  return {
    id: row.id,
    adapterId: row.adapter_id,
    harness: row.harness,
    state: row.state,
    repoRoot: row.repo_root,
    startedAt: row.started_at,
    endedAt: row.ended_at,
    snapshot,
    workerCount: Array.isArray(snapshot && snapshot.workers) ? snapshot.workers.length : 0,
  };
}

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Strip circular references before persisting: build a fresh plain object picking only the fields you need.
  2. Convert BigInt values to String or Number before serializing, or use a replacer: JSON.stringify(value, (_, v) => typeof v === 'bigint' ? v.toString() : v).
  3. Use util.inspect or a safe-stringify library to detect circular structure at debug time, then fix the source shape.
  4. Unit-test the serialization path with a representative payload so the failure surfaces before it reaches the DB writer.

Example fix

// before
stringifyJson(sessionWithCircularRef, 'snapshot');
// -> Failed to serialize snapshot: Converting circular structure to JSON

// after
const { snapshot } = sessionWithCircularRef;
const safeSnapshot = {
  workers: (snapshot.workers || []).map(({ name, status, branch }) => ({ name, status, branch })),
};
stringifyJson(safeSnapshot, 'snapshot');
Defensive patterns

Strategy: try-catch

Validate before calling

function isSafeJson(value) {
  try {
    JSON.stringify(value);
    return true;
  } catch {
    return false;
  }
}

if (!isSafeJson(snapshot)) {
  // strip known circular fields or build a plain-object copy
  snapshot = { workers: snapshot.workers.map(w => ({ name: w.name, status: w.status })) };
}
stringifyJson(snapshot, 'snapshot');

Type guard

function isPlainSerializable(value, seen = new WeakSet()) {
  if (value === null || typeof value !== 'object') return true;
  if (typeof value === 'function' || typeof value === 'bigint') return false;
  if (seen.has(value)) return false;
  seen.add(value);
  return Object.values(value).every(v => isPlainSerializable(v, seen));
}

Try / catch

try {
  stringifyJson(value, label);
} catch (error) {
  if (/Failed to serialize/.test(error.message)) {
    // fall back to a safe replacer or drop the field
    return JSON.stringify(value, (_, v) => typeof v === 'bigint' ? v.toString() : v);
  }
  throw error;
}

Prevention

When it happens

Trigger: Passing an object with a circular reference (e.g. a session object that references itself, a DOM-like node, or an object that includes its parent); passing a value containing a BigInt (JSON.stringify throws on BigInt by default); passing a value with a .toJSON() that itself throws.

Common situations: Storing a session snapshot that inadvertently includes the parent session record; serializing a worker plan whose templateVariables reference the plan object; mixing BigInt row IDs into a JSON payload after a migration to bigint; a custom class whose toJSON override errors on missing fields.

Related errors


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