JuliusBrussee/caveman · error

openclaw fresh config cannot route through Caveman without $

Error message

openclaw fresh config cannot route through Caveman without ${requiredKey}

What it means

freshOpenClawModelRef builds a fresh (non-migrated) openclaw model reference routed through Caveman. In managed mode it requires env var CAVE_API_KEY; otherwise OPENAI_API_KEY. firstEnvSecret checks the variable exists and has non-whitespace content; missing/blank means the request cannot authenticate upstream, so config generation fails fast.

Source

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

}

function openClawDefaultApiKey(providerId: string): string | undefined {
  return openClawSecretString(OPENCLAW_WELL_KNOWN_PROVIDERS[providerId]?.apiKey);
}

function openClawProviderApiKey(providerId: string, provider: JsonObject): string | undefined {
  return openClawSecretString(provider.apiKey) ?? openClawDefaultApiKey(providerId);
}

function openClawResolvedProviderApiKey(providerId: string, provider: JsonObject): string | undefined {
  const key = openClawProviderApiKey(providerId, provider);
  return key ? resolveEnvTemplate(key) : undefined;
}

function freshOpenClawModelRef(ctx: OverlayBuilderContext): OpenClawModelRef {
  const requiredKey = ctx.mode === "managed" ? "CAVE_API_KEY" : "OPENAI_API_KEY";
  if (!firstEnvSecret(ctx.env, [requiredKey])) {
    throw new Error(`openclaw fresh config cannot route through Caveman without ${requiredKey}`);
  }
  return { provider: "openai", model: OPENCLAW_FRESH_MODEL, raw: `openai/${OPENCLAW_FRESH_MODEL}` };
}

function appendUrlPath(base: string, path: string): string {
  return `${base.replace(/\/+$/, "")}${path}`;
}

function codexHomeDir(): string {
  return join(homedir(), ".codex");
}

function codexAuthPath(): string {
  return join(codexHomeDir(), "auth.json");
}

function nonEmptyString(v: unknown): v is string {
  return typeof v === "string" && v.trim().length > 0;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Export the required key: `export CAVE_API_KEY=...` (managed) or `export OPENAI_API_KEY=...` (self-hosted) and regenerate
  2. If using a .env loader, ensure it runs before openclaw config generation
  3. Provision the secret in CI/secret manager for managed deployments
  4. Verify with `printenv CAVE_API_KEY` / `printenv OPENAI_API_KEY` that the value is set and non-blank

Example fix

# before
openclaw config  # Error: cannot route through Caveman without CAVE_API_KEY

# after
export CAVE_API_KEY="$(devkey run cave-api-key -- echo $CAVE_API_KEY)"  # or source from secret store
openclaw config
Defensive patterns

Strategy: validation

Validate before calling

const requiredKey = mode === "managed" ? "CAVE_API_KEY" : "OPENAI_API_KEY";
const value = process.env[requiredKey];
if (typeof value !== "string" || value.trim() === "") {
  throw new Error(`set ${requiredKey} before generating openclaw config`);
}

Type guard

function hasEnvSecret(env: NodeJS.ProcessEnv, key: string): env is Record<string, string> & Record<typeof key, string> {
  const v = env[key];
  return typeof v === "string" && v.trim().length > 0;
}

Try / catch

try {
  const ref = freshOpenClawModelRef(ctx);
} catch (error) {
  if (/cannot route through Caveman without/.test((error as Error).message)) {
    throw new Error(`missing credential: load it via devkey/secret manager, then retry`, { cause: error });
  }
  throw error;
}

Prevention

When it happens

Trigger: Generating a fresh openclaw config (managed mode → no CAVE_API_KEY; self-hosted mode → no OPENAI_API_KEY) in the environment passed as ctx.env. Only presence of a trimmed non-empty string is checked, not validity.

Common situations: Running openclaw config generation in a shell/CI without exporting the key; key present only in a .env file that is not loaded; managed-mode deployment forgetting to provision CAVE_API_KEY; whitespace-only value.

Related errors


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