JuliusBrussee/caveman · error

managed Gemini CLI routing is unsupported because Gemini CLI

Error message

managed Gemini CLI routing is unsupported because Gemini CLI cannot send separate Caveman and upstream credentials

What it means

geminiNativeMutations() hard-refuses managed mode up front: wrapMode(gw) === "managed" means credentials flow through a managed gateway, but Gemini CLI cannot send separate Caveman and upstream credentials, so there is no safe way to route it. This is a designed capability gap, not a corrupted state.

Source

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

  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);
  const settings = parseJsonFileObject(settingsPath, settingsBefore);
  assertNativeHooksShape(settingsPath, settings, "gemini");
  if (settings.mcpServers !== undefined && (typeof settings.mcpServers !== "object" || settings.mcpServers === null || Array.isArray(settings.mcpServers))) {
    throw new Error(`${settingsPath} mcpServers must be a JSON object; refusing to overwrite it`);
  }
  const servers = settings.mcpServers && typeof settings.mcpServers === "object" && !Array.isArray(settings.mcpServers)
    ? settings.mcpServers as Record<string, unknown>
    : {};
  const previousMcp = servers.caveman;
  const installedMcp = { command: mcpBinary, args: [] };
  servers.caveman = installedMcp;
  settings.mcpServers = servers;
  const withHooks = nativeHooksDocument("gemini", true, settings);

  const envPath = join(homedir(), ".gemini", ".env");

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Use a local gateway (default wrap mode) for Gemini: point the integration at a locally running caveman instance
  2. Change the gateway configuration so wrapMode resolves to "local" for the Gemini install command
  3. Keep Gemini un-integrated on managed setups — this limitation is intentional and has no config workaround

Example fix

# before
$ caveman native install gemini --gateway https://managed.example.com  # wrap mode: managed -> throws

# after
$ caveman serve &  # local gateway
$ caveman native install gemini  # local wrap mode, succeeds
Defensive patterns

Strategy: validation

Validate before calling

function gatewaySupportsGemini(gatewayUrl: string): boolean {
  // managed wrap mode is a hard capability gap for Gemini
  return new URL(gatewayUrl).hostnameIsLocalOrLoopback(); // local wrap mode only
}

Try / catch

try { nativeInstallGemini(gateway); } catch (e) {
  if (e instanceof Error && /managed Gemini CLI routing is unsupported/.test(e.message)) {
    skipOrUseLocalGateway("gemini"); // no retry: capability gap, not transient
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a gateway URL whose wrap mode resolves to "managed" (e.g. a shared/remote caveman gateway) to the native Gemini integration command.

Common situations: Pointing caveman at a team-managed gateway via config/env and then trying to enable Gemini native routing; reusing gateway settings copied from a managed deployment.

Related errors


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