JuliusBrussee/caveman · error
registry output has invalid capability
Error message
registry output has invalid capability
What it means
loadTransformRegistry() validates each entry of the engine registry's capabilities array: transform_id must be a string and eligible_segment_kinds must be an array of strings. Any entry failing this shape throws 'registry output has invalid capability'. This fail-closed validation prevents malformed engine output from entering lock evidence and route planning.
Solutions
- Run 'caveman setup' (or reinstall) so the engine and registry schema match what the agent adapter expects
- Point CAVEMAN_ENGINE_BIN at a compatible engine binary version
- Inspect 'caveman-engine registry' output and fix the offending capability entry if you own a custom engine
Example fix
// before (engine output)
{"capabilities":[{"id":"terminal","segment_kinds":["tool_result"]}]}
// after
{"capabilities":[{"transform_id":"terminal","eligible_segment_kinds":["tool_result"]}]} Defensive patterns
Strategy: validation
Validate before calling
function capabilityIsValid(c: unknown): c is { transform_id: string; eligible_segment_kinds: string[] } {
const cap = c as { transform_id?: unknown; eligible_segment_kinds?: unknown };
return typeof cap?.transform_id === "string" &&
Array.isArray(cap.eligible_segment_kinds) &&
cap.eligible_segment_kinds.every((k) => typeof k === "string");
}
const parsed = JSON.parse(await engineRegistryOutput());
if (!parsed.capabilities.every(capabilityIsValid)) console.error("engine registry schema mismatch"); Type guard
function capabilityIsValid(c: unknown): c is { transform_id: string; eligible_segment_kinds: string[] } {
const cap = c as { transform_id?: unknown; eligible_segment_kinds?: unknown };
return typeof cap?.transform_id === "string" &&
Array.isArray(cap.eligible_segment_kinds) &&
cap.eligible_segment_kinds.every((k) => typeof k === "string");
} Try / catch
try {
await loadTransformRegistry();
} catch (error) {
if ((error as Error).message.includes("invalid capability")) {
console.error("Engine registry schema mismatch — reinstall a compatible engine:");
await runCavemanSetup();
return await loadTransformRegistry();
}
throw error;
} Prevention
- Match engine binary version to the agent package version
- Avoid hand-editing engine registry output
- Validate custom engine builds against the expected capability schema before deploying
When it happens
Trigger: Calling loadTransformRegistry when any capability in the engine's registry JSON has a missing/non-string transform_id, a missing/non-array eligible_segment_kinds, or non-string elements inside eligible_segment_kinds.
Common situations: A custom/incompatible CAVEMAN_ENGINE_BIN emitting a different capability schema (e.g. 'id' instead of 'transform_id'); a hand-edited or partially migrated engine registry; an engine version newer/older than the adapter expects.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- cave_transform_registry_unavailable
- registry output has no valid registry_sha256
- cave_transform_registry_unavailable: run caveman setup or…
- registry output has no capabilities
- agent conformance fixtures must cover claude and pi
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/a862a2c897540cf6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/cli.ts:1123
});
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(
`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();View on GitHub (pinned to 3ee70a1026)