{"record":{"id":"dfeb968733e56d7b","repo":"JuliusBrussee/caveman","slug":"caveman-bedrock-endpoint-must-be-runtime-or-mantle","errorCode":null,"errorMessage":"CAVEMAN_BEDROCK_ENDPOINT must be runtime or mantle","messagePattern":"CAVEMAN_BEDROCK_ENDPOINT must be runtime or mantle","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":8441,"sourceCode":"  if (!accessKey || !secretKey) {\n    throw new Error(\"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set together\");\n  }\n  return [accessKey, secretKey, ...(sessionToken ? [sessionToken] : [])].join(\":\");\n}\n\n// applyClaudeBedrockWrap selects Claude Code's native Bedrock or opt-in Mantle\n// transport only when the operator explicitly requests it. The default Claude\n// profile remains Anthropic-wire. Runtime uses Claude Code's documented AWS\n// credential chain; unlike Mantle, Claude Code exposes no supported Runtime\n// authentication-bypass variable. In managed mode the validated BYOK value also\n// rides through Claude's custom headers. Stored-only, server-injected Claude\n// Code auth therefore uses Mantle's documented gateway mode.\nfunction applyClaudeBedrockWrap(env: NodeJS.ProcessEnv, agent: AgentProfile, renderedGw: string, modeGw: string): boolean {\n  if (agent.id !== \"claude\" || process.env.CAVEMAN_WRAP_PROVIDER?.trim().toLowerCase() !== \"bedrock\") return false;\n\n  const endpoint = process.env.CAVEMAN_BEDROCK_ENDPOINT?.trim().toLowerCase() || \"runtime\";\n  if (endpoint !== \"runtime\" && endpoint !== \"mantle\") {\n    throw new Error(\"CAVEMAN_BEDROCK_ENDPOINT must be runtime or mantle\");\n  }\n\n  // Remove the generic/profile Anthropic route and any stale Bedrock selection\n  // inherited from the shell. Exactly one Claude Code provider lane is active.\n  for (const key of WRAP_BASE_URL_ENV_VARS) delete env[key];\n  delete env.ANTHROPIC_AUTH_TOKEN;\n  delete env.CLAUDE_CODE_USE_BEDROCK;\n  // Remove stale values if a caller previously relied on this undocumented\n  // variable. We intentionally never set it.\n  delete env.CLAUDE_CODE_SKIP_BEDROCK_AUTH;\n  delete env.ANTHROPIC_BEDROCK_BASE_URL;\n  delete env.CLAUDE_CODE_USE_MANTLE;\n  delete env.CLAUDE_CODE_SKIP_MANTLE_AUTH;\n  delete env.ANTHROPIC_BEDROCK_MANTLE_BASE_URL;\n\n  const bedrockBase = appendUrlPath(renderedGw, \"/bedrock\");\n  if (endpoint === \"mantle\") {\n    env.CLAUDE_CODE_USE_MANTLE = \"1\";","sourceCodeStart":8423,"sourceCodeEnd":8459,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/2f49f0e1a352aa810e70056b7930aeb0b3d219b4/packages/cli/src/index.ts#L8423-L8459","documentation":"When CAVEMAN_WRAP_PROVIDER=bedrock selects the Bedrock transport for Claude wrap, CAVEMAN_BEDROCK_ENDPOINT chooses the lane: 'runtime' (Claude Code native Bedrock, the default when unset/empty) or 'mantle' (Claude Code's Mantle transport pointed at the gateway's /bedrock/anthropic adapter). The value is trimmed and lowercased before comparison, so only genuinely other strings throw; anything else is a typo or a stale value from an older Caveman that accepted different names.","triggerScenarios":"`caveman wrap claude` / `caveman claude` with CAVEMAN_WRAP_PROVIDER=bedrock and CAVEMAN_BEDROCK_ENDPOINT set to a non-empty string other than runtime/mantle — e.g. 'bedrock', 'gateway', 'native', 'local', or a URL like http://127.0.0.1:3777/bedrock.","commonSituations":"Copying an endpoint URL into the wrong variable; values left over from an older release or an internal build that spelled the lane differently; scripts parameterizing the endpoint name with a typo.","solutions":["Use one of the two lane names: `export CAVEMAN_BEDROCK_ENDPOINT=runtime` or `export CAVEMAN_BEDROCK_ENDPOINT=mantle`","If you wanted the default, just unset it: `unset CAVEMAN_BEDROCK_ENDPOINT` (empty/unset means runtime)","Double-check you did not mean CAVEMAN_WRAP_PROVIDER (selects bedrock at all) or a gateway URL variable — URLs do not belong in CAVEMAN_BEDROCK_ENDPOINT","Search your shell profile and CI env for the stray export and remove it"],"exampleFix":"# before: lane typo / URL in the lane variable\nexport CAVEMAN_WRAP_PROVIDER=bedrock\nexport CAVEMAN_BEDROCK_ENDPOINT=bedrock   # or http://127.0.0.1:3777/bedrock\ncaveman claude\n# >> CAVEMAN_BEDROCK_ENDPOINT must be runtime or mantle\n\n# after: valid lane (or unset for the default)\nexport CAVEMAN_BEDROCK_ENDPOINT=runtime\ncaveman claude","handlingStrategy":"validation","validationCode":"const BEDROCK_ENDPOINTS = new Set(['runtime', 'mantle']);\nconst raw = process.env.CAVEMAN_BEDROCK_ENDPOINT;\nconst endpoint = raw?.trim().toLowerCase() || 'runtime';\nif (process.env.CAVEMAN_WRAP_PROVIDER === 'bedrock' && !BEDROCK_ENDPOINTS.has(endpoint)) {\n  throw new Error(`CAVEMAN_BEDROCK_ENDPOINT must be one of ${[...BEDROCK_ENDPOINTS].join('|')} (or unset)`);\n}","typeGuard":"const isBedrockEndpointLane = (v: unknown): v is 'runtime' | 'mantle' =>\n  v === undefined || v === '' || v === 'runtime' || v === 'mantle';","tryCatchPattern":"catch (err) { if (err.message.includes('must be runtime or mantle')) { /* unset the variable (default runtime) or set it to a lane name — URLs and synonyms are rejected */ } else throw err; }","preventionTips":["Keep a project allowlist of caveman env vars and validate them at script start","Remember the domain: lane names only — runtime (default) or mantle; URLs belong in gateway config","Grep shell rc files and CI env blocks after upgrading caveman for variables whose vocab changed"],"tags":["bedrock","env-var","invalid-value","claude","wrap"],"backgroundTag":"invalid-env-var-value","analyzedSha":"2f49f0e1a352aa810e70056b7930aeb0b3d219b4","analyzedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-08-21T10:36:37.832Z"}