JuliusBrussee/caveman · error · Error
cave_transform_registry_unavailable: run caveman setup or…
Error message
cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (${error instanceof Error ? error.message : String(error)}) What it means
`loadTransformRegistry` shells out to the engine binary (`process.env.CAVEMAN_ENGINE_BIN ?? "caveman-engine"`) with args `["registry"]`, a 10-second timeout and 2 MiB maxBuffer, then requires stdout to be JSON with a 64-hex `registry_sha256` and a non-empty `capabilities` array of well-formed entries. Every failure mode — binary not found (spawn ENOENT), timeout, non-zero exit, invalid JSON, bad shape — is wrapped into this single error with the underlying message appended in parentheses.
Solutions
- Run `caveman setup` to install/bootstrap the engine
- Set CAVEMAN_ENGINE_BIN to the absolute path of a working engine binary
- Verify manually: `$CAVEMAN_ENGINE_BIN registry` must print JSON with a 64-hex registry_sha256 and non-empty capabilities within 10 s
- In CI, cache the engine install and export CAVEMAN_ENGINE_BIN in the job environment
Example fix
# before export CAVEMAN_ENGINE_BIN=engine # not on PATH → spawn ENOENT # after npx caveman setup # installs engine and prints its path export CAVEMAN_ENGINE_BIN=/usr/local/bin/caveman-engine
Defensive patterns
Strategy: validation
Validate before calling
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const bin = process.env.CAVEMAN_ENGINE_BIN ?? "caveman-engine";
// Fail fast with a clear message before the build wraps it:
const { stdout } = await execFileAsync(bin, ["registry"], { timeout: 10_000 });
const parsed = JSON.parse(stdout); // must contain 64-hex registry_sha256 + capabilities[] Try / catch
try { await run("npm run build"); } catch (e) {
if (e instanceof Error && e.message.startsWith("cave_transform_registry_unavailable")) {
// underlying cause is in the parenthesized suffix; remedy: caveman setup or set CAVEMAN_ENGINE_BIN, then retry once
} else throw e;
} Prevention
- Run `caveman setup` in your Dockerfile/CI setup step
- Pin CAVEMAN_ENGINE_BIN to an absolute path in CI
- Use `caveman doctor` to verify engine registry readiness before build jobs
When it happens
Trigger: `caveman build`/`check`/`dev` (anything reaching `transformRegistrySHA256()`) on a machine where the engine binary is not installed or not on PATH; CAVEMAN_ENGINE_BIN pointing at a wrong or non-executable path; the engine `registry` subcommand emitting malformed JSON, zero capabilities, or timing out past 10 s.
Common situations: Fresh clone without `caveman setup`; CI image with a stripped PATH; engine binary updated so registry output changed; typo in CAVEMAN_ENGINE_BIN.
Related errors
- cave_transform_registry_unavailable
- ENOENT
- not found on PATH
- registry output has invalid capability
- registry output has no capabilities
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/716771fc228f5327.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/cli.ts:1132
throw new Error("registry output has no valid registry_sha256");
}
if (!Array.isArray(parsed.capabilities) || parsed.capabilities.length === 0) {
throw new Error("registry output has no capabilities");
}
const capabilities = parsed.capabilities.map((capability): TransformCapability => {
if (typeof capability.transform_id !== "string" ||
!Array.isArray(capability.eligible_segment_kinds) ||
capability.eligible_segment_kinds.some((kind) => typeof kind !== "string")) {
throw new Error("registry output has invalid capability");
}
return {
transformID: capability.transform_id,
segmentKinds: capability.eligible_segment_kinds as TransformCapability["segmentKinds"],
};
});
return { sha256: parsed.registry_sha256, capabilities };
} catch (error) {
throw new Error(
`cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (${error instanceof Error ? error.message : String(error)})`,
);
}
}
async function engineEntitled(): Promise<boolean> {
const command = process.env.CAVEMAN_CLI_BIN ?? "caveman";
try {
const env = buildRuntimeControlEnv();
const invocation = portableInvocation(command, ["status", "--json"], { env });
const { stdout } = await execFileAsync(invocation.command, [...invocation.args], {
encoding: "utf8",
env,
maxBuffer: 2 << 20,
timeout: 10_000,
});
const parsed = JSON.parse(stdout) as { mode?: unknown; seat?: { entitled?: unknown } };
return parsed.seat?.entitled === true && parsed.mode === "compress";View on GitHub (pinned to 766dce6b13)