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
- Supply the JSONL path: `caveman audit eval-import ./evidence.jsonl`
- Prefix leading-dash filenames with `./` so they parse as positionals
- 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
- Fail CI when a required file argument resolves to an empty string
- Pre-check `test -s "$EVIDENCE"` so missing and empty files surface early
- Prefix leading-dash filenames with ./
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
- usage: ${invokedCommand("audit")} import --format <fmt> <fil
- eval evidence file exceeds 4 MiB batch limit
- eval evidence batch exceeds 1000 records
- eval evidence file contains no records
- caveman compress --toon-stats is unavailable; use --toon to
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-18).
Data as JSON: /api/errors/2285a31008d68407.
Report an issue: GitHub.