{"record":{"id":"f3124a80fa709e67","repo":"JuliusBrussee/caveman","slug":"registry-output-has-no-valid-registry-sha256","errorCode":null,"errorMessage":"registry output has no valid registry_sha256","messagePattern":"registry output has no valid registry_sha256","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1114,"sourceCode":"  const command = process.env.CAVEMAN_ENGINE_BIN ?? \"caveman-engine\";\n  try {\n    const env = buildEngineEnv();\n    const invocation = portableInvocation(command, [\"registry\"], { env });\n    const { stdout } = await execFileAsync(invocation.command, [...invocation.args], {\n      encoding: \"utf8\",\n      env,\n      maxBuffer: 2 << 20,\n      timeout: 10_000,\n    });\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(","sourceCodeStart":1096,"sourceCodeEnd":1132,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/cli.ts#L1096-L1132","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nexport CAVEMAN_ENGINE_BIN=/usr/local/bin/old-engine\n// after (after running caveman setup)\nexport CAVEMAN_ENGINE_BIN=$HOME/.caveman/bin/caveman-engine","handlingStrategy":"type-guard","validationCode":"function isValidRegistrySha(value: unknown): value is string {\n  return typeof value === \"string\" && /^[0-9a-f]{64}$/.test(value);\n}\n// before relying on the engine:\nconst out = await engineRegistryOutput();\nconst parsed = JSON.parse(out);\nif (!isValidRegistrySha(parsed.registry_sha256)) {\n  console.error(\"engine binary incompatible or corrupt; run caveman setup\");\n}","typeGuard":"function hasValidRegistrySha(parsed: unknown): parsed is { registry_sha256: string; capabilities: unknown[] } {\n  const p = parsed as { registry_sha256?: unknown };\n  return typeof p?.registry_sha256 === \"string\" && /^[0-9a-f]{64}$/.test(p.registry_sha256);\n}","tryCatchPattern":"try {\n  await loadTransformRegistry();\n} catch (error) {\n  if ((error as Error).message.includes(\"no valid registry_sha256\")) {\n    await runCavemanSetup(); // reinstall/upgrade engine\n    return await loadTransformRegistry();\n  }\n  throw error;\n}","preventionTips":["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"],"tags":["engine","registry","validation","subprocess"],"backgroundTag":"unexpected-response-shape","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"}