JuliusBrussee/caveman · error · Error
eval evidence import failed (${response.status}): ${JSON.str
Error message
eval evidence import failed (${response.status}): ${JSON.stringify(body)} What it means
The eval-evidence batch POST to /api/v1/eval-evidence/batches returned a non-2xx status. The CLI surfaces the HTTP status code and the parsed response body verbatim, so the server's own error message is always visible. Auth, CSRF, project-scope, and per-record validation failures all surface through this single throw.
Source
Thrown at packages/cli/src/index.ts:17181
if (items.length === 0) throw new Error("eval evidence file contains no records");
const cfg = await config();
const project = flagFrom(argv, "--project", cfg.projectId ?? "");
const response = await fetch(`${cfg.baseURL}/api/v1/eval-evidence/batches`, {
method: "POST",
headers: {
authorization: `Bearer ${cfg.token}`,
"content-type": "application/json",
"x-cave-csrf": "cli",
},
body: JSON.stringify({
...(project ? { project_id: project } : {}),
dry_run: argv.includes("--dry-run"),
items,
}),
});
const body = await response.json();
if (!response.ok) throw new Error(`eval evidence import failed (${response.status}): ${JSON.stringify(body)}`);
print(body);
}
// ---------------------------------------------------------------------------
// Signed usage receipts: air-gapped export + offline verification.
//
// A receipt is a per-(org,project,day) aggregate, Ed25519-signed and chained by
// prev_receipt_hash. `verify` recomputes each canonical hash, checks the
// signature against the published public key, and walks the chain — all offline,
// so finance (either party) can re-derive trust without contacting Caveman. It is
// the cross-language counterpart of cloud/metering's VerifyChain.
// ---------------------------------------------------------------------------
type ReceiptSignature = { alg: string; key_id: string; sig: string };
type ReceiptScope = { org_hash: string; project_hash: string };
type ReceiptOptimizer = { optimizer_id_hash: string; requests_optimized: number };
type Receipt = {
schema: string;View on GitHub (pinned to 5184b3d11a)
Solutions
- Read the embedded body — it carries the server's actual reason
- On 401/403: run `caveman login` again and retry the import
- On 400/404: fix the project uuid or the record fields named in the body
- For persistent failures: compare CLI and server versions for validation drift
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight auth and project scope before the big upload.
const me = await fetch(`${cfg.baseURL}/api/v1/me`, { headers: { authorization: `Bearer ${cfg.token}` } });
if (!me.ok) throw new Error('token invalid — re-login before import'); Try / catch
try {
await postBatch(items);
} catch (e) {
const msg = (e as Error).message;
const status = Number(/\((\d+)\)/.exec(msg)?.[1] ?? 0);
if (status === 401) {
await relogin();
await postBatch(items); // idempotent retry once auth is refreshed
} else throw e;
} Prevention
- Re-login immediately before long-running CI imports
- Validate the project uuid format (and its existence) before upload
- Log the response body verbatim — it is the server's diagnosis
When it happens
Trigger: 401/403 from an expired or wrong bearer token; 400 when the server rejects record shapes or the project_id; 404 for an unknown project uuid; 413/422 when server-side caps trip; an intermediary proxy replacing the body.
Common situations: Token expiring between login and import in long CI runs; typo'd --project uuid; server updated with stricter validation than the CLI expects; corporate proxies mangling responses.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- cave plan fetch failed with HTTP ${response.status}
- device authorization failed: HTTP ${codeResponse.status}
- usage: ${invokedCommand("audit")} eval-import <evidence.json
- eval evidence file exceeds 4 MiB batch limit
- eval evidence line ${index + 1} is not valid JSON
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-18).
Data as JSON: /api/errors/94bef159b6aa1488.
Report an issue: GitHub.