JuliusBrussee/caveman · error

existing Gemini Caveman routing block is corrupted; run `cav

Error message

existing Gemini Caveman routing block is corrupted; run `caveman doctor gemini`

What it means

geminiNativeEnv() strips and rewrites the managed routing block in ~/.gemini/.env delimited by GEMINI_NATIVE_ENV_BEGIN/GEMINI_NATIVE_ENV_END markers. It throws when exactly one marker is missing (XOR) or END appears before BEGIN — i.e. the managed block was partially deleted or reordered, so idempotent re-stamping is unsafe.

Source

Thrown at packages/cli/src/index.ts:6089

      kind: "claude-settings",
      owned: { route, previous_route: previousRoute ?? null },
    },
    {
      file: mcpPath,
      before: mcpBefore,
      after: Buffer.from(JSON.stringify(mcpRoot, null, 2) + "\n"),
      kind: "claude-mcp",
      owned: { installed_mcp: installedMcp, previous_mcp: previousMcp ?? null },
    },
  ];
}

function geminiNativeEnv(source: string, route: string): { text: string; block: string } {
  let stripped = source;
  const start = stripped.indexOf(GEMINI_NATIVE_ENV_BEGIN);
  const finish = stripped.indexOf(GEMINI_NATIVE_ENV_END);
  if ((start === -1) !== (finish === -1) || (start !== -1 && finish < start)) {
    throw new Error("existing Gemini Caveman routing block is corrupted; run `caveman doctor gemini`");
  }
  if (start !== -1) stripped = `${stripped.slice(0, start)}${stripped.slice(finish + GEMINI_NATIVE_ENV_END.length)}`.trim();
  const block = [
    GEMINI_NATIVE_ENV_BEGIN,
    `GEMINI_BASE_URL=${route}`,
    `GOOGLE_GEMINI_BASE_URL=${route}`,
    `GOOGLE_VERTEX_BASE_URL=${appendUrlPath(route, "/vertex")}`,
    GEMINI_NATIVE_ENV_END,
  ].join("\n");
  return { text: `${stripped}${stripped ? "\n\n" : ""}${block}\n`, block };
}

function geminiNativeMutations(gw: string, mcpBinary: string): NativeMutation[] {
  if (wrapMode(gw) === "managed") {
    throw new Error("managed Gemini CLI routing is unsupported because Gemini CLI cannot send separate Caveman and upstream credentials");
  }
  const settingsPath = geminiSettingsPath();
  const settingsBefore = fileBytes(settingsPath);

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Run `caveman doctor gemini` to repair or remove the corrupted block
  2. Manually open ~/.gemini/.env and delete the orphaned GEMINI_NATIVE_ENV marker line(s) so neither remains, then retry the install
  3. If unsure which lines are Caveman-owned, remove everything between (and including) both marker styles and let the next install re-stamp cleanly

Example fix

# before — ~/.gemini/.env
>>> CAVEMAN NATIVE ENV BEGIN >>>
GEMINI_BASE_URL=http://127.0.0.1:8080/w/gemini
# (END marker was deleted by hand)

# after — marker lines fully removed, then re-run install to re-stamp
GEMINI_BASE_URL=http://127.0.0.1:8080/w/gemini
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from "node:fs";
function geminiEnvMarkersBalanced(path: string): boolean {
  let src: string;
  try { src = readFileSync(path, "utf8"); } catch { return true; }
  const b = src.indexOf(GEMINI_NATIVE_ENV_BEGIN);
  const e = src.indexOf(GEMINI_NATIVE_ENV_END);
  return (b === -1) === (e === -1) && (b === -1 || e > b);
}

Try / catch

try { nativeInstallGemini(); } catch (e) {
  if (e instanceof Error && /Gemini Caveman routing block is corrupted/.test(e.message)) {
    spawnSync("caveman", ["doctor", "gemini"], { stdio: "inherit" });
    nativeInstallGemini();
  } else throw e;
}

Prevention

When it happens

Trigger: Enabling/re-enabling native Gemini routing when ~/.gemini/.env contains GEMINI_NATIVE_ENV_BEGIN without its END (or vice versa), or the END marker appears earlier in the file than BEGIN.

Common situations: User manually deleted part of the Caveman block while tidying the env file; a merge conflict or editor truncation; earlier uninstall removed only one marker.

Related errors


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