JuliusBrussee/caveman · error · Error

usage: ${invokedCommand("audit")} eval-import <evidence.json

Error message

usage: ${invokedCommand("audit")} eval-import <evidence.jsonl> [--project <uuid>] [--dry-run]

What it means

Usage guard for `caveman audit eval-import`: after skipping the `--project` option, the CLI requires one positional path to a newline-delimited evidence file. When only flags remain (no positional), this usage error throws before the file is opened. The command turns source-neutral eval records into one bounded batch stamped server-side with tenant scope and external-only authority.

Source

Thrown at packages/cli/src/index.ts:17143

    "content-type": "application/octet-stream",
    "x-cave-csrf": "cli"
  };
  const fieldMap = flagFrom(argv, "--field-map", "");
  if (fieldMap) headers["x-cave-field-map"] = fieldMap;
  const response = await fetch(`${cfg.baseURL}/api/v1/imports?format=${encodeURIComponent(format)}`, {
    method: "POST",
    headers,
    body: data
  });
  print(await response.json());
}

// auditEvalImport turns newline-delimited, source-neutral eval records into one
// bounded batch. Server stamps tenant scope, observed basis, and external-only
// authority; CI cannot promote its own results into rollout authority.
async function auditEvalImport(argv: string[]) {
  const file = positionalAfterOptions(argv.slice(1), new Set(["--project"]));
  if (!file) throw new Error(`usage: ${invokedCommand("audit")} eval-import <evidence.jsonl> [--project <uuid>] [--dry-run]`);
  const data = await readFile(file);
  if (data.byteLength > 4 * 1024 * 1024) throw new Error("eval evidence file exceeds 4 MiB batch limit");

  const items: Record<string, unknown>[] = [];
  for (const [index, rawLine] of data.toString("utf8").split(/\r?\n/).entries()) {
    const line = rawLine.trim();
    if (!line) continue;
    let parsed: unknown;
    try {
      parsed = JSON.parse(line);
    } catch {
      throw new Error(`eval evidence line ${index + 1} is not valid JSON`);
    }
    if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
      throw new Error(`eval evidence line ${index + 1} must be a JSON object`);
    }
    items.push(parsed as Record<string, unknown>);
    if (items.length > 1000) throw new Error("eval evidence batch exceeds 1000 records");

View on GitHub (pinned to 5184b3d11a)

Solutions

  1. Supply the JSONL path: `caveman audit eval-import ./evidence.jsonl`
  2. Prefix leading-dash filenames with `./` so they parse as positionals
  3. Echo the full command in CI before execution to catch missing paths

Example fix

# before
caveman audit eval-import --dry-run
# after
caveman audit eval-import --dry-run ./evidence.jsonl
Defensive patterns

Strategy: validation

Validate before calling

const file = positionalAfterOptions(argv.slice(1), new Set(['--project']));
if (!file) {
  console.error('usage: caveman audit eval-import <evidence.jsonl> [--project <uuid>] [--dry-run]');
  process.exit(2);
}

Prevention

When it happens

Trigger: `caveman audit eval-import --project <uuid>` without a file; the evidence path passed through an unset variable; a filename starting with `--` being consumed as an option.

Common situations: CI steps templating the file path; artifacts with leading-dash filenames; argument-order churn between CLI versions.

Understand the failure class

Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-18). Data as JSON: /api/errors/2285a31008d68407. Report an issue: GitHub.