{"record":{"id":"a862a2c897540cf6","repo":"JuliusBrussee/caveman","slug":"registry-output-has-invalid-capability","errorCode":null,"errorMessage":"registry output has invalid capability","messagePattern":"registry output has invalid capability","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1123,"sourceCode":"    });\n    const parsed = JSON.parse(stdout) as {\n      registry_sha256?: unknown;\n      capabilities?: Array<{\n        transform_id?: unknown;\n        eligible_segment_kinds?: unknown;\n      }>;\n    };\n    if (typeof parsed.registry_sha256 !== \"string\" || !/^[0-9a-f]{64}$/.test(parsed.registry_sha256)) {\n      throw new Error(\"registry output has no valid registry_sha256\");\n    }\n    if (!Array.isArray(parsed.capabilities) || parsed.capabilities.length === 0) {\n      throw new Error(\"registry output has no capabilities\");\n    }\n    const capabilities = parsed.capabilities.map((capability): TransformCapability => {\n      if (typeof capability.transform_id !== \"string\" ||\n          !Array.isArray(capability.eligible_segment_kinds) ||\n          capability.eligible_segment_kinds.some((kind) => typeof kind !== \"string\")) {\n        throw new Error(\"registry output has invalid capability\");\n      }\n      return {\n        transformID: capability.transform_id,\n        segmentKinds: capability.eligible_segment_kinds as TransformCapability[\"segmentKinds\"],\n      };\n    });\n    return { sha256: parsed.registry_sha256, capabilities };\n  } catch (error) {\n    throw new Error(\n      `cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (${error instanceof Error ? error.message : String(error)})`,\n    );\n  }\n}\n\nasync function engineEntitled(): Promise<boolean> {\n  const command = process.env.CAVEMAN_CLI_BIN ?? \"caveman\";\n  try {\n    const env = buildRuntimeControlEnv();","sourceCodeStart":1105,"sourceCodeEnd":1141,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/cli.ts#L1105-L1141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (engine output)\n{\"capabilities\":[{\"id\":\"terminal\",\"segment_kinds\":[\"tool_result\"]}]}\n// after\n{\"capabilities\":[{\"transform_id\":\"terminal\",\"eligible_segment_kinds\":[\"tool_result\"]}]}","handlingStrategy":"validation","validationCode":"function capabilityIsValid(c: unknown): c is { transform_id: string; eligible_segment_kinds: string[] } {\n  const cap = c as { transform_id?: unknown; eligible_segment_kinds?: unknown };\n  return typeof cap?.transform_id === \"string\" &&\n    Array.isArray(cap.eligible_segment_kinds) &&\n    cap.eligible_segment_kinds.every((k) => typeof k === \"string\");\n}\nconst parsed = JSON.parse(await engineRegistryOutput());\nif (!parsed.capabilities.every(capabilityIsValid)) console.error(\"engine registry schema mismatch\");","typeGuard":"function capabilityIsValid(c: unknown): c is { transform_id: string; eligible_segment_kinds: string[] } {\n  const cap = c as { transform_id?: unknown; eligible_segment_kinds?: unknown };\n  return typeof cap?.transform_id === \"string\" &&\n    Array.isArray(cap.eligible_segment_kinds) &&\n    cap.eligible_segment_kinds.every((k) => typeof k === \"string\");\n}","tryCatchPattern":"try {\n  await loadTransformRegistry();\n} catch (error) {\n  if ((error as Error).message.includes(\"invalid capability\")) {\n    console.error(\"Engine registry schema mismatch — reinstall a compatible engine:\");\n    await runCavemanSetup();\n    return await loadTransformRegistry();\n  }\n  throw error;\n}","preventionTips":["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"],"tags":["engine","registry","schema-validation","subprocess"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}