{"record":{"id":"5b31b82bd079a6b0","repo":"JuliusBrussee/caveman","slug":"openclaw-fresh-config-cannot-route-through-caveman","errorCode":null,"errorMessage":"openclaw fresh config cannot route through Caveman without ${requiredKey}","messagePattern":"openclaw fresh config cannot route through Caveman without (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":5494,"sourceCode":"}\n\nfunction openClawDefaultApiKey(providerId: string): string | undefined {\n  return openClawSecretString(OPENCLAW_WELL_KNOWN_PROVIDERS[providerId]?.apiKey);\n}\n\nfunction openClawProviderApiKey(providerId: string, provider: JsonObject): string | undefined {\n  return openClawSecretString(provider.apiKey) ?? openClawDefaultApiKey(providerId);\n}\n\nfunction openClawResolvedProviderApiKey(providerId: string, provider: JsonObject): string | undefined {\n  const key = openClawProviderApiKey(providerId, provider);\n  return key ? resolveEnvTemplate(key) : undefined;\n}\n\nfunction freshOpenClawModelRef(ctx: OverlayBuilderContext): OpenClawModelRef {\n  const requiredKey = ctx.mode === \"managed\" ? \"CAVE_API_KEY\" : \"OPENAI_API_KEY\";\n  if (!firstEnvSecret(ctx.env, [requiredKey])) {\n    throw new Error(`openclaw fresh config cannot route through Caveman without ${requiredKey}`);\n  }\n  return { provider: \"openai\", model: OPENCLAW_FRESH_MODEL, raw: `openai/${OPENCLAW_FRESH_MODEL}` };\n}\n\nfunction appendUrlPath(base: string, path: string): string {\n  return `${base.replace(/\\/+$/, \"\")}${path}`;\n}\n\nfunction codexHomeDir(): string {\n  return join(homedir(), \".codex\");\n}\n\nfunction codexAuthPath(): string {\n  return join(codexHomeDir(), \"auth.json\");\n}\n\nfunction nonEmptyString(v: unknown): v is string {\n  return typeof v === \"string\" && v.trim().length > 0;","sourceCodeStart":5476,"sourceCodeEnd":5512,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L5476-L5512","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Export the required key: `export CAVE_API_KEY=...` (managed) or `export OPENAI_API_KEY=...` (self-hosted) and regenerate","If using a .env loader, ensure it runs before openclaw config generation","Provision the secret in CI/secret manager for managed deployments","Verify with `printenv CAVE_API_KEY` / `printenv OPENAI_API_KEY` that the value is set and non-blank"],"exampleFix":"# before\nopenclaw config  # Error: cannot route through Caveman without CAVE_API_KEY\n\n# after\nexport CAVE_API_KEY=\"$(devkey run cave-api-key -- echo $CAVE_API_KEY)\"  # or source from secret store\nopenclaw config","handlingStrategy":"validation","validationCode":"const requiredKey = mode === \"managed\" ? \"CAVE_API_KEY\" : \"OPENAI_API_KEY\";\nconst value = process.env[requiredKey];\nif (typeof value !== \"string\" || value.trim() === \"\") {\n  throw new Error(`set ${requiredKey} before generating openclaw config`);\n}","typeGuard":"function hasEnvSecret(env: NodeJS.ProcessEnv, key: string): env is Record<string, string> & Record<typeof key, string> {\n  const v = env[key];\n  return typeof v === \"string\" && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  const ref = freshOpenClawModelRef(ctx);\n} catch (error) {\n  if (/cannot route through Caveman without/.test((error as Error).message)) {\n    throw new Error(`missing credential: load it via devkey/secret manager, then retry`, { cause: error });\n  }\n  throw error;\n}","preventionTips":["Reference credentials by name through a secret loader (devkey) instead of relying on ambient shell env","Assert required env keys at process start, not deep in config generation","In CI, fail the job early on missing CAVE_API_KEY/OPENAI_API_KEY with a clear message"],"tags":["openclaw","api-key","environment","fail-fast"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}