JuliusBrussee/caveman · error · Error
empty version output
Error message
empty version output
What it means
runtimeVersionDiagnostic() parses the stdout of an external `caveman` runtime CLI to build a human-readable version string. Trimmed stdout was empty — the process produced no output — so there is nothing to report and it throws instead of fabricating a version. Any non-empty output is handled (JSON with version/binary_release, or a legacy plain line).
Source
Thrown at packages/agent/src/cli.ts:431
function compareNodeVersion(current: string, minimum: string): number {
const parse = (value: string) => value.split(".").slice(0, 3).map((part) => Number(part));
const left = parse(current);
const right = parse(minimum);
for (let index = 0; index < 3; index++) {
const difference = (left[index] ?? 0) - (right[index] ?? 0);
if (difference !== 0) return difference;
}
return 0;
}
function safeDiagnostic(error: unknown): string {
const value = error instanceof Error ? error.message : String(error);
return value.replace(/[\r\n]+/g, " ").slice(0, 512);
}
function runtimeVersionDiagnostic(stdout: string): string {
const value = stdout.trim();
if (value === "") throw new Error("empty version output");
try {
const parsed = JSON.parse(value) as { version?: unknown; binary_release?: unknown };
if (typeof parsed.version === "string" && parsed.version.trim() !== "") {
const release = typeof parsed.binary_release === "string" && parsed.binary_release.trim() !== ""
? ` (${parsed.binary_release.trim()})`
: "";
return `caveman ${parsed.version.trim()}${release}`;
}
} catch {
// Older CLIs may return one plain version line.
}
return value.replace(/[\r\n]+/g, " ").slice(0, 256);
}
function credentialForModel(model: string): { name: string; available: boolean } {
const provider = model.split("/", 1)[0];
if (provider === "anthropic") {
return { name: "ANTHROPIC_API_KEY", available: Boolean(process.env.ANTHROPIC_API_KEY) };View on GitHub (pinned to 27d5a3981a)
Solutions
- Run the runtime binary directly (`caveman --version` or equivalent) and confirm it prints a version; if empty, reinstall it.
- Check PATH ordering for stub scripts shadowing the real caveman binary (which -a caveman).
- If a wrapper script is involved, make sure it forwards stdout instead of consuming it.
Example fix
# before: shim swallows output #!/bin/sh exec /opt/caveman/bin/caveman "$@" >/dev/null # stdout discarded # after #!/bin/sh exec /opt/caveman/bin/caveman "$@"
Defensive patterns
Strategy: validation
Validate before calling
import { execFileSync } from "node:child_process";
function assertRuntimeReportsVersion(bin = "caveman"): string {
const out = execFileSync(bin, ["--version"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
if (out === "") throw new Error(`${bin} produced no version output; check PATH shim`);
return out;
} Prevention
- Smoke-test `caveman --version` in CI before jobs that probe the runtime version.
- Audit PATH for wrapper scripts that discard stdout (which -a caveman).
- Reinstall the runtime binary if it crashes before printing — empty output means a broken install, not a parse quirk.
When it happens
Trigger: The version-probe subprocess (caveman runtime CLI) exits producing zero bytes on stdout: binary found but broken (crashes before printing), wrong executable shadowing the real one (an empty stub script earlier in PATH), or output redirected/swallowed by a wrapper.
Common situations: PATH pointing at a shim/wrapper script that swallows stdout; a half-installed or architecture-mismatched binary that dies silently; CI layer caching a truncated binary; Windows batch shim quirks.
Related errors
- register requires CAVE_CONTROL_URL, CAVE_TOKEN, and CAVE_PRO
- no provider credential detected; pass --provider
- multiple provider credentials detected; pass --provider
- Claude call failed: {e.stderr}
- cache-replay: verifier process failed
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/dc3471466a9ca00e.
Report an issue: GitHub.