JuliusBrussee/caveman · error

cave_transform_registry_unavailable

cave_transform_registry_unavailable

Error message

cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (${error instanceof Error ? error.message : String(error)})

What it means

loadTransformRegistry() wraps every failure of the engine registry lookup (spawn failure, timeout, bad JSON, any of the validation throws above) into a single error 'cave_transform_registry_unavailable: run caveman setup or set CAVEMAN_ENGINE_BIN (...)' with the original message as context. The framework needs the transform registry to compute lock identity and plan routes, so an unavailable engine fails closed with a remediation hint.

Solutions

  1. Run 'caveman setup' to install the engine binary and registry (the error's prescribed fix)
  2. Set CAVEMAN_ENGINE_BIN to the absolute path of a working caveman-engine binary
  3. Verify 'caveman-engine registry' runs manually and emits valid JSON quickly (<10s)
  4. Check PATH in CI/shell so the engine is reachable, or fix permissions on the binary

Example fix

// before (shell)
caveman build  # ENOENT: caveman-engine not found
// after
export CAVEMAN_ENGINE_BIN=/opt/caveman/bin/caveman-engine
caveman build
Defensive patterns

Strategy: try-catch

Validate before calling

import { accessSync, constants } from "node:fs";
const bin = process.env.CAVEMAN_ENGINE_BIN ?? "caveman-engine";
try {
  accessSync(bin.includes("/") ? bin : which(bin) ?? bin, constants.X_OK);
} catch {
  console.error(`engine binary '${bin}' not executable/found — run caveman setup or set CAVEMAN_ENGINE_BIN`);
}

Try / catch

try {
  await loadTransformRegistry();
} catch (error) {
  if ((error as Error).message.startsWith("cave_transform_registry_unavailable")) {
    console.error("Engine unavailable:", (error as Error).message);
    // degrade (observe-only) or provision:
    await runCavemanSetup();
    return await loadTransformRegistry();
  }
  throw error;
}

Prevention

When it happens

Trigger: Any failure inside loadTransformRegistry: the engine binary is not on PATH (ENOENT), CAVEMAN_ENGINE_BIN points at a missing/non-executable file, the registry call exceeds the 10s timeout or 2MiB buffer, stdout is not valid JSON, or one of the registry_sha256/capabilities validation checks throws.

Common situations: Fresh machine where 'caveman setup' was never run; engine uninstalled or moved; CI container missing the engine; slow engine exceeding the 10s timeout; shadowing 'caveman-engine' on PATH with an unrelated program.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/456479d273eadbc6. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/cli.ts:1132

      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();
    const invocation = portableInvocation(command, ["status", "--json"], { env });
    const { stdout } = await execFileAsync(invocation.command, [...invocation.args], {
      encoding: "utf8",
      env,
      maxBuffer: 2 << 20,
      timeout: 10_000,
    });
    const parsed = JSON.parse(stdout) as { mode?: unknown; seat?: { entitled?: unknown } };
    return parsed.seat?.entitled === true && parsed.mode === "compress";

View on GitHub (pinned to 3ee70a1026)