JuliusBrussee/caveman · error · Error

cave_vercel_terminal_failure

cave_vercel_terminal_failure

Error message

cave_vercel_terminal_failure

What it means

defaultCCRPath creates the CAVEMAN_HOME directory (or ~/.caveman) with MkdirAll(0700) so the first run succeeds; any mkdir failure is wrapped as 'create %s: %w'. This is a filesystem permission or path problem: the parent path is not writable, a path component is a file, or the filesystem is read-only.

Source

Thrown at packages/agent/src/adapters.ts:213

export function createVercelAISDKAdapter(
  identity: HarnessAdapterIdentity,
  agent: VercelToolLoopAgentBinding,
): HarnessAdapter {
  assertSupportedUpstream(identity, VERCEL_AI_SDK_VERSION, "vercel", "ai");
  return createHarnessAdapter("vercel-ai-sdk", identity, {
    package: "ai",
    class: "ToolLoopAgent",
    method: "generate",
    usage: "LanguageModelUsage.v4",
  }, async (request) => {
    const startedAt = performance.now();
    const response = await agent.generate({
      prompt: request.prompt,
      ...(request.signal === undefined ? {} : { abortSignal: request.signal }),
    });
    if (response.error !== undefined || terminalFinishReason(response.finishReason) === false) {
      throw new Error("cave_vercel_terminal_failure");
    }
    const expected = expectedProviderModel(request.plan);
    const actualModel = normalizedResponseModel(response.response?.modelId, expected.provider);
    return harnessExecution({
      request,
      text: response.text,
      provider: expected.provider,
      model: actualModel,
      usage: usageFromAISDK(response.usage, request.plan.reasoning !== "none"),
      latencyMs: Math.round(performance.now() - startedAt),
    });
  });
}

export interface EveMessageResponseBinding {
  result(): Promise<{
    message: string | undefined;
    status: "completed" | "failed" | "waiting";

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Pre-create the directory and grant write access to the running user: mkdir -p /var/lib/caveman && chown <user> /var/lib/caveman.
  2. Point CAVEMAN_HOME (or CAVEMAN_CCR_DB) at a writable volume, e.g. an emptyDir or mounted PVC in Kubernetes.
  3. Remove any regular file occupying the intended directory path.

Example fix

# before
CAVEMAN_HOME=/var/lib/caveman caveman-shrink < in.json
# create /var/lib/caveman: permission denied

# after
sudo mkdir -p /var/lib/caveman && sudo chown "$USER" /var/lib/caveman
CAVEMAN_HOME=/var/lib/caveman caveman-shrink < in.json
Defensive patterns

Strategy: validation

Validate before calling

// Go callers: ensure the CAVEMAN_HOME parent exists and is writable
home := os.Getenv("CAVEMAN_HOME")
if home == "" {
    h, _ := os.UserHomeDir()
    home = filepath.Join(h, ".caveman")
}
if fi, err := os.Stat(filepath.Dir(home)); err != nil || !fi.IsDir() {
    return fmt.Errorf("cannot create %s: parent missing or not a directory", home)
}
if err := os.MkdirAll(home, 0o700); err != nil {
    return fmt.Errorf("pre-create %s failed: %w", home, err)
}

Prevention

When it happens

Trigger: Calling Shrink with CAVEMAN_HOME set to a location whose parents are not writable (e.g. /etc/caveman as non-root), CAVEMAN_HOME pointing at an existing regular file, or a read-only filesystem such as a container rootfs.

Common situations: Setting CAVEMAN_HOME=/var/lib/caveman without creating/granting it; pointing CAVEMAN_HOME into a path where a file already exists; read-only root filesystems in hardened Kubernetes pods; disk quota exhaustion.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/5be1f7fe47be181a. Report an issue: GitHub.