JuliusBrussee/caveman · error
registry output has no valid registry_sha256
Error message
registry output has no valid registry_sha256
What it means
loadTransformRegistry() shells out to the caveman-engine binary ('registry' subcommand, or CAVEMAN_ENGINE_BIN) and validates its JSON stdout. The registry_sha256 field must be a 64-char lowercase hex string; otherwise it throws 'registry output has no valid registry_sha256'. This fail-closed check ensures the registry fingerprint used in lock evidence is a real digest, not missing or malformed output from a broken/incompatible engine.
Solutions
- Run 'caveman setup' to install/update the engine binary and its registry
- Set CAVEMAN_ENGINE_BIN to the correct caveman-engine binary path if a nonstandard install is used
- Check 'caveman-engine registry' manually — if its stdout is not clean JSON with a 64-hex registry_sha256, fix or reinstall the engine
Example fix
// before export CAVEMAN_ENGINE_BIN=/usr/local/bin/old-engine // after (after running caveman setup) export CAVEMAN_ENGINE_BIN=$HOME/.caveman/bin/caveman-engine
Defensive patterns
Strategy: type-guard
Validate before calling
function isValidRegistrySha(value: unknown): value is string {
return typeof value === "string" && /^[0-9a-f]{64}$/.test(value);
}
// before relying on the engine:
const out = await engineRegistryOutput();
const parsed = JSON.parse(out);
if (!isValidRegistrySha(parsed.registry_sha256)) {
console.error("engine binary incompatible or corrupt; run caveman setup");
} Type guard
function hasValidRegistrySha(parsed: unknown): parsed is { registry_sha256: string; capabilities: unknown[] } {
const p = parsed as { registry_sha256?: unknown };
return typeof p?.registry_sha256 === "string" && /^[0-9a-f]{64}$/.test(p.registry_sha256);
} Try / catch
try {
await loadTransformRegistry();
} catch (error) {
if ((error as Error).message.includes("no valid registry_sha256")) {
await runCavemanSetup(); // reinstall/upgrade engine
return await loadTransformRegistry();
}
throw error;
} Prevention
- Run 'caveman-engine registry' manually after installing/upgrading the engine
- Never wrap CAVEMAN_ENGINE_BIN in scripts that print extra output to stdout
- Pin the engine version alongside the framework version
When it happens
Trigger: Running loadTransformRegistry (called during validLockIdentity/lock checks) when the engine binary outputs JSON whose registry_sha256 is absent, non-string, or does not match /^[0-9a-f]{64}$/ — e.g. an old engine version, an error message on stdout, or a wrapper script printing extra text.
Common situations: CAVEMAN_ENGINE_BIN pointing at an outdated or wrong binary; engine not fully set up (setup not run) so it prints a partial payload; a shell wrapper or version banner polluting stdout; a different tool occupying the 'caveman-engine' name on PATH.
Related errors
- cave_transform_registry_unavailable
- registry output has invalid capability
- registry output has no capabilities
- Cave Build lock is stale or invalid; refusing Claude launch…
- cave_transform_registry_unavailable: run caveman setup or…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/f3124a80fa709e67.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/cli.ts:1114
const command = process.env.CAVEMAN_ENGINE_BIN ?? "caveman-engine";
try {
const env = buildEngineEnv();
const invocation = portableInvocation(command, ["registry"], { env });
const { stdout } = await execFileAsync(invocation.command, [...invocation.args], {
encoding: "utf8",
env,
maxBuffer: 2 << 20,
timeout: 10_000,
});
const parsed = JSON.parse(stdout) as {
registry_sha256?: unknown;
capabilities?: Array<{
transform_id?: unknown;
eligible_segment_kinds?: unknown;
}>;
};
if (typeof parsed.registry_sha256 !== "string" || !/^[0-9a-f]{64}$/.test(parsed.registry_sha256)) {
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(View on GitHub (pinned to 3ee70a1026)