coleam00/Archon · error

Corrupt commands JSON for codebase ${id}: unable to parse st

Error message

Corrupt commands JSON for codebase ${id}: unable to parse stored data. Run UPDATE remote_agent_codebases SET commands = '{}' WHERE id = '${id}' to reset.

What it means

getCodebaseCommands reads the `commands` column of remote_agent_codebases and, when it is stored as a string, parses it as JSON. If parsing fails the stored data is corrupt, so it throws with the codebase id and a literal SQL statement the operator can run to reset commands to '{}'. The library refuses to guess or silently swallow malformed persisted data.

Source

Thrown at packages/core/src/db/codebases.ts:78

    [JSON.stringify(commands), id]
  );
}

export async function getCodebaseCommands(
  id: string
): Promise<Record<string, { path: string; description: string }>> {
  const result = await pool.query<{
    commands: Record<string, { path: string; description: string }> | string;
  }>('SELECT commands FROM remote_agent_codebases WHERE id = $1', [id]);
  const raw = result.rows[0]?.commands;
  // SQLite returns TEXT columns as strings; PostgreSQL JSONB returns objects
  let parsed: Record<string, { path: string; description: string }>;
  if (typeof raw === 'string') {
    try {
      parsed = JSON.parse(raw);
    } catch (err) {
      getLog().error({ codebaseId: id, raw, err }, 'db.codebase_commands_json_parse_failed');
      throw new Error(
        `Corrupt commands JSON for codebase ${id}: unable to parse stored data. ` +
          `Run UPDATE remote_agent_codebases SET commands = '{}' WHERE id = '${id}' to reset.`
      );
    }
  } else {
    parsed = raw ?? {};
  }
  // Spread to ensure mutable copy - Bun's SQLite driver returns frozen objects
  return { ...parsed };
}

export async function registerCommand(
  id: string,
  name: string,
  command: { path: string; description: string }
): Promise<void> {
  const commands = await getCodebaseCommands(id);
  commands[name] = command;

View on GitHub (pinned to 0773b97458)

Solutions

  1. Run the suggested reset: UPDATE remote_agent_codebases SET commands = '{}' WHERE id = '<id>'; then re-add commands via the API.
  2. Inspect the raw value first (SELECT commands FROM remote_agent_codebases WHERE id='<id>') and fix the JSON syntax if recoverable (trailing commas, unescaped quotes).
  3. Check application logs for db.codebase_commands_json_parse_failed entries — they include the raw value and parse error.
  4. Validate any manual writes with SELECT commands::jsonb ... or jsonb_set to let PostgreSQL reject bad JSON at write time.
  5. Backfill rows from a backup if the original commands matter and the corruption is old.

Example fix

-- before: corrupt value
SELECT commands FROM remote_agent_codebases WHERE id='abc'; -- "{path: x, }"
-- after: reset to empty object per the error's guidance
UPDATE remote_agent_codebases SET commands = '{}' WHERE id = 'abc';
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight sanity check on the stored value before calling getCodebaseCommands
const { rows } = await pool.query('SELECT commands FROM remote_agent_codebases WHERE id = $1', [id]);
const raw = rows[0]?.commands;
if (typeof raw === 'string') {
  try { JSON.parse(raw); } catch { await pool.query("UPDATE remote_agent_codebases SET commands = '{}' WHERE id = $1", [id]); }
}

Type guard

function isCommandsRecord(v: unknown): v is Record<string, { path: string; description: string }> {
  return !!v && typeof v === 'object' && !Array.isArray(v) &&
    Object.values(v).every(e => !!e && typeof e === 'object' && typeof e.path === 'string' && typeof e.description === 'string');
}

Try / catch

let commands;
try {
  commands = await getCodebaseCommands(id);
} catch (e) {
  if (e.message.startsWith('Corrupt commands JSON')) {
    await pool.query("UPDATE remote_agent_codebases SET commands = '{}' WHERE id = $1", [id]);
    commands = await getCodebaseCommands(id); // reset worked
  } else throw e;
}

Prevention

When it happens

Trigger: The commands column for the given codebase id contains a non-JSON string (hand-edited row, truncated write, legacy serialization) and JSON.parse throws.

Common situations: Manual UPDATE/INSERT with malformed JSON; a migration or older binary wrote a different format; a partially applied write from a crashed process; pasting JSON with trailing commas or single quotes into psql.

Understand the failure class

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/743aaf5ae594815d. Report an issue: GitHub.