{"record":{"id":"716771fc228f5327","repo":"JuliusBrussee/caveman","slug":"cave-transform-registry-unavailable-run-caveman-s","errorCode":null,"errorMessage":"cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (${error instanceof Error ? error.message : String(error)})","messagePattern":"cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1132,"sourceCode":"      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();\n    const invocation = portableInvocation(command, [\"status\", \"--json\"], { 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 { mode?: unknown; seat?: { entitled?: unknown } };\n    return parsed.seat?.entitled === true && parsed.mode === \"compress\";","sourceCodeStart":1114,"sourceCodeEnd":1150,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/agent/src/cli.ts#L1114-L1150","documentation":"`loadTransformRegistry` shells out to the engine binary (`process.env.CAVEMAN_ENGINE_BIN ?? \"caveman-engine\"`) with args `[\"registry\"]`, a 10-second timeout and 2 MiB maxBuffer, then requires stdout to be JSON with a 64-hex `registry_sha256` and a non-empty `capabilities` array of well-formed entries. Every failure mode — binary not found (spawn ENOENT), timeout, non-zero exit, invalid JSON, bad shape — is wrapped into this single error with the underlying message appended in parentheses.","triggerScenarios":"`caveman build`/`check`/`dev` (anything reaching `transformRegistrySHA256()`) on a machine where the engine binary is not installed or not on PATH; CAVEMAN_ENGINE_BIN pointing at a wrong or non-executable path; the engine `registry` subcommand emitting malformed JSON, zero capabilities, or timing out past 10 s.","commonSituations":"Fresh clone without `caveman setup`; CI image with a stripped PATH; engine binary updated so registry output changed; typo in CAVEMAN_ENGINE_BIN.","solutions":["Run `caveman setup` to install/bootstrap the engine","Set CAVEMAN_ENGINE_BIN to the absolute path of a working engine binary","Verify manually: `$CAVEMAN_ENGINE_BIN registry` must print JSON with a 64-hex registry_sha256 and non-empty capabilities within 10 s","In CI, cache the engine install and export CAVEMAN_ENGINE_BIN in the job environment"],"exampleFix":"# before\nexport CAVEMAN_ENGINE_BIN=engine   # not on PATH → spawn ENOENT\n# after\nnpx caveman setup                    # installs engine and prints its path\nexport CAVEMAN_ENGINE_BIN=/usr/local/bin/caveman-engine","handlingStrategy":"validation","validationCode":"import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nconst execFileAsync = promisify(execFile);\nconst bin = process.env.CAVEMAN_ENGINE_BIN ?? \"caveman-engine\";\n// Fail fast with a clear message before the build wraps it:\nconst { stdout } = await execFileAsync(bin, [\"registry\"], { timeout: 10_000 });\nconst parsed = JSON.parse(stdout); // must contain 64-hex registry_sha256 + capabilities[]","typeGuard":null,"tryCatchPattern":"try { await run(\"npm run build\"); } catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"cave_transform_registry_unavailable\")) {\n    // underlying cause is in the parenthesized suffix; remedy: caveman setup or set CAVEMAN_ENGINE_BIN, then retry once\n  } else throw e;\n}","preventionTips":["Run `caveman setup` in your Dockerfile/CI setup step","Pin CAVEMAN_ENGINE_BIN to an absolute path in CI","Use `caveman doctor` to verify engine registry readiness before build jobs"],"tags":["engine","spawn","path","setup","registry"],"backgroundTag":"executable-not-found","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}