{"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":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":9276,"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":9258,"sourceCodeEnd":9294,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L9258-L9294","documentation":"applyClaudeBedrockWrap validates CAVEMAN_BEDROCK_ENDPOINT when CAVEMAN_WRAP_PROVIDER is \"bedrock\" for the claude agent. The variable accepts only \"runtime\" (default) or \"mantle\"; any other value is rejected because the wrapper can only remove the generic Anthropic route and wire exactly one of these two documented transport lanes.","triggerScenarios":"Setting CAVEMAN_WRAP_PROVIDER=bedrock and CAVEMAN_BEDROCK_ENDPOINT to something like a full https:// URL, \"bedrock-runtime\", \"eu\", or a typo such as \"Runtime\" beyond trimming/lowercasing is handled, so only genuinely different strings throw.","commonSituations":"Operators pasting a regional Bedrock endpoint URL into the variable assuming it wants an actual endpoint; typos like \"mantle-gw\"; copying the variable name from another tool's docs.","solutions":["Set CAVEMAN_BEDROCK_ENDPOINT=runtime (or remove it — \"runtime\" is the default).","Set CAVEMAN_BEDROCK_ENDPOINT=mantle if you specifically want Claude Code's Mantle gateway transport.","Do not put a real AWS endpoint URL in this variable; it is a mode selector, not a URL.","Check casing after trimming/lowercasing is applied — \"RUNTIME\" is fine, \"runtime-fips\" is not."],"exampleFix":"// before\nexport CAVEMAN_BEDROCK_ENDPOINT=\"https://bedrock-runtime.us-east-1.amazonaws.com\"\n// after\nexport CAVEMAN_BEDROCK_ENDPOINT=\"runtime\"","handlingStrategy":"validation","validationCode":"const ep = (process.env.CAVEMAN_BEDROCK_ENDPOINT ?? \"runtime\").trim().toLowerCase();\nif (process.env.CAVEMAN_WRAP_PROVIDER?.trim().toLowerCase() === \"bedrock\" && ep !== \"runtime\" && ep !== \"mantle\") {\n  throw new Error(`CAVEMAN_BEDROCK_ENDPOINT='${ep}' invalid; use \"runtime\" or \"mantle\"`);\n}","typeGuard":"function isBedrockEndpoint(v: string | undefined): v is \"runtime\" | \"mantle\" {\n  const s = (v ?? \"runtime\").trim().toLowerCase();\n  return s === \"runtime\" || s === \"mantle\";\n}","tryCatchPattern":"try {\n  applyClaudeBedrockWrap(env, agent, renderedGw, modeGw);\n} catch (e) {\n  if (String((e as Error).message).startsWith(\"CAVEMAN_BEDROCK_ENDPOINT must be\")) {\n    // fall back to default: delete the variable and retry with \"runtime\"\n  }\n}","preventionTips":["Treat CAVEMAN_BEDROCK_ENDPOINT as a mode flag (runtime|mantle), never a URL.","Remove the variable entirely to get the documented default (runtime).","Add the allowed values to deployment docs/scripts that set CAVEMAN_WRAP_PROVIDER=bedrock.","Normalize casing yourself (lowercase, trimmed) in wrapper scripts."],"tags":["env","bedrock","claude","invalid-enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}