JuliusBrussee/caveman · error · Error

Claude ANTHROPIC_BASE_URL changed after enable; refusing des

Error message

Claude ANTHROPIC_BASE_URL changed after enable; refusing destructive disable

What it means

For claude-settings, disable tolerates env.ANTHROPIC_BASE_URL only when it is absent or exactly the caveman route recorded in the journal (owned.route, e.g. <gateway>/w/claude). Any other value means you repointed Claude while the integration was active; removing the caveman env block would silently clobber your URL, so disable refuses.

Source

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

  const before = nativeBackupBytes(operation);
  if (!current) {
    if (operation.before_exists) throw new Error(`${operation.file} was removed after enable; refusing destructive disable`);
    return null;
  }
  if (bytesHash(current) === operation.after_sha256) return before;

  if (operation.kind === "claude-settings") {
    const currentRoot = parseJsonFileObject(operation.file, current);
    const beforeRoot = parseJsonFileObject(operation.file, before);
    const currentEnv = currentRoot.env && typeof currentRoot.env === "object" && !Array.isArray(currentRoot.env)
      ? currentRoot.env as Record<string, unknown>
      : {};
    const beforeEnv = beforeRoot.env && typeof beforeRoot.env === "object" && !Array.isArray(beforeRoot.env)
      ? beforeRoot.env as Record<string, unknown>
      : {};
    const route = operation.owned?.route;
    if (currentEnv.ANTHROPIC_BASE_URL !== undefined && currentEnv.ANTHROPIC_BASE_URL !== route) {
      throw new Error("Claude ANTHROPIC_BASE_URL changed after enable; refusing destructive disable");
    }
    if (currentEnv.ANTHROPIC_BASE_URL === route) {
      if (beforeEnv.ANTHROPIC_BASE_URL === undefined) delete currentEnv.ANTHROPIC_BASE_URL;
      else currentEnv.ANTHROPIC_BASE_URL = beforeEnv.ANTHROPIC_BASE_URL;
    }
    // The first-party assertion is only ever written when the user carried no
    // value of their own, so restore is a plain removal — but only while the
    // value is still exactly ours; a user's later edit outlives disable.
    const assume = operation.owned?.assume_first_party;
    if (typeof assume === "string" && currentEnv[CLAUDE_ASSUME_FIRST_PARTY_ENV] === assume) {
      delete currentEnv[CLAUDE_ASSUME_FIRST_PARTY_ENV];
    }
    // Symmetric to the enable-side ENABLE_TOOL_SEARCH write: only withdraw the
    // value we introduced ourselves and only while it is still untouched, so a
    // user who set their own afterwards keeps it.
    if (beforeEnv.ENABLE_TOOL_SEARCH === undefined && currentEnv.ENABLE_TOOL_SEARCH === TOOL_SEARCH_DEFAULT) {
      delete currentEnv.ENABLE_TOOL_SEARCH;
    }

View on GitHub (pinned to 2f49f0e1a3)

Solutions

  1. If the new URL is wanted: copy it out, delete the ANTHROPIC_BASE_URL key (or set it back to the caveman route), run `caveman disable claude`, then set your URL.
  2. If you meant to keep caveman: restore the route from the journal (owned.route in ~/.caveman/integrations/claude.json) or run `caveman doctor claude --fix`.
  3. For temporary rerouting prefer `caveman wrap claude` sessions over editing enabled settings.

Example fix

// before ~/.claude/settings.json
"env": { "ANTHROPIC_BASE_URL": "https://my-other-proxy" }

// after - key removed (or restored to the caveman route), then `caveman disable claude`
"env": {}
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'node:fs';
const settings = JSON.parse(readFileSync(`${process.env.HOME}/.claude/settings.json`, 'utf8'));
const journal = JSON.parse(readFileSync(`${process.env.HOME}/.caveman/integrations/claude.json`, 'utf8'));
const route = journal.operations.find((o: any) => o.kind === 'claude-settings')?.owned?.route;
const url = settings?.env?.ANTHROPIC_BASE_URL;
if (url !== undefined && url !== route) { console.error('ANTHROPIC_BASE_URL diverged from the caveman route; revert or delete it before disable'); process.exit(1); }

Prevention

When it happens

Trigger: `caveman disable claude` after editing ~/.claude/settings.json to set env.ANTHROPIC_BASE_URL to a different proxy or the direct API base while caveman routing was installed.

Common situations: Temporarily bypassing caveman by editing settings instead of disabling; switching to another gateway; scripts that manage the base URL in settings.json.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@2f49f0e1a3 (2026-08-18). Data as JSON: /api/errors/f88fcdbae9dd5c68. Report an issue: GitHub.