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

  1. Run 'caveman setup' (or reinstall) so the engine and registry schema match what the agent adapter expects
  2. Point CAVEMAN_ENGINE_BIN at a compatible engine binary version
  3. 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

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


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)