tinyhumansai/openhuman · error · Error

unknown option: ${arg}

Error message

unknown option: ${arg}

What it means

harness-cache-audit.mjs parses argv with a closed switch; any unmatched token reaches `default:` and throws `unknown option: <arg>` before any RPC or core spawn happens. Unlike goals-live.mjs's parser, there is no eslint fall-through comment because -h/--help exit directly, but the behavior is the same fail-fast contract.

Source

Thrown at scripts/debug/harness-cache-audit.mjs:129

        break;
      case "--min-hit-rate":
        opts.minHitRate = parseNonNegativeNumber(next(), "--min-hit-rate");
        break;
      case "--max-turns-without-cache":
        opts.maxTurnsWithoutCache = parseNonNegativeInt(
          next(),
          "--max-turns-without-cache",
        );
        break;
      case "--verbose":
        opts.verbose = true;
        break;
      case "-h":
      case "--help":
        console.log(usage());
        process.exit(0);
      default:
        throw new Error(`unknown option: ${arg}`);
    }
  }
  return opts;
}

function parsePositiveInt(raw, label) {
  const value = Number(raw);
  if (!Number.isInteger(value) || value < 1)
    throw new Error(`${label} must be a positive integer`);
  return value;
}

function parseNonNegativeInt(raw, label) {
  const value = Number(raw);
  if (!Number.isInteger(value) || value < 0)
    throw new Error(`${label} must be a non-negative integer`);
  return value;
}

View on GitHub (pinned to a221052e0d)

Solutions

  1. Run `node scripts/debug/harness-cache-audit.mjs --help` and use only the listed options
  2. Move goals-specific flags (--case, --context) to scripts/debug/goals-live.mjs
  3. Fix the typo / remove the stray dash
  4. If the flag should exist, add the case plus a usage() line

Example fix

# before
node scripts/debug/harness-cache-audit.mjs --case list
# Error: unknown option: --case

# after
node scripts/debug/goals-live.mjs --case list
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set([
  "--core-url", "--token", "--workspace", "--turns", "--model", "--thread-id",
  "--rpc-timeout-ms", "--prompt", "--spawn-core", "--isolated-workspace",
  "--keep-workspace", "--min-hit-rate", "--max-turns-without-cache", "--verbose", "-h", "--help",
]);
const unknown = process.argv.slice(2).filter((a) => /^--?\w/.test(a) && !SUPPORTED.has(a));
if (unknown.length) { console.error(`unsupported: ${unknown.join(" ")}`); process.exit(2); }

Type guard

const isAuditFlag = (f) =>
  /^--(core-url|token|workspace|turns|model|thread-id|rpc-timeout-ms|prompt|spawn-core|isolated-workspace|keep-workspace|min-hit-rate|max-turns-without-cache|verbose|help)$|^(-h)$/.test(f);

Prevention

When it happens

Trigger: Passing goals-live-only flags to this script: `--case list`, `--context`, `--reset`, `--show-thoughts`; typos like `--spawncore`; removed/renamed flags from older revisions; double-dash `---verbose`.

Common situations: Command lines copied between the sibling debug runners (goals-live.mjs, agent-prepare-context-audit.mjs, harness-subagent-rpc-audit.mjs) that share a flag family but not an identical set; stale shell history after flags were added.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/241172578a7f9687. Report an issue: GitHub.