
【Bug已解决】API Error 400 invalid beta flag when trying to use Claude Code with Bedrock using claude 3.5 haiku 解决方案一、现象长什么样你用 Claude Code或anthropicSDK通过 AWS Bedrock 调用 Claude 3.5 Haiku却收到API Error: 400 invalid beta flag或400 {type:error,error:{type:invalid_request_error,message:invalid beta flag}}在直连api.anthropic.com时一切正常一旦切到 Bedrock 就报这个你并没主动设置任何 beta但 Claude Code 默认会带一些anthropic-beta头比如为 prompt caching、或某个预览特性报错只在特定模型/特定调用路径出现比如启用了某个需要 beta 的能力computer use、extended thinking 等时。一句话Claude Code / SDK 默认携带的anthropic-beta请求头Bedrock 的 InvokeModel 通道不认识于是返回 400 invalid beta flag。二、背景Anthropic 用anthropic-beta请求头来开启预览/实验性特性如prompt-caching-2024-07-31、max-tokens-3-5-sonnet-2024-07-15。直连 Anthropic 官方 API 时带上这些头是合法的服务端会按 beta 处理。但当你通过AWS Bedrock调用时请求是走 Bedrock 的InvokeModel/Converse通道由 Bedrock 再做一层转发。Bedrock 不接受、也不会透传anthropic-beta头——它只认 Bedrock 自己的头如x-amzn-bedrock-*而把anthropic-beta视为非法字段返回 400 invalid beta flag。Claude Code 这类工具为了统一体验默认可能在请求里塞 beta 头一旦目标后端是 Bedrock这些头就成了毒药。三、根因根因是同一套客户端代码对官方 endpoint和Bedrock endpoint发送了相同的anthropic-beta头而 Bedrock 不接纳它# 伪代码客户端无条件带 beta 头 headers { x-api-key: key, anthropic-version: 2023-06-01, anthropic-beta: prompt-caching-2024-07-31, # 直连 OKBedrock 报错 } # 当 base_url 指向 Bedrock 网关时这个头导致 400修复方向当后端是 Bedrock 时移除anthropic-beta头Bedrock 上对应能力通过 Bedrock 自己的方式开启不需要这个头。四、最小可运行复现from dataclasses import dataclass from typing import Dict, Optional def build_headers(base_url: str, beta: Optional[str] prompt-caching-2024-07-31) - Dict[str, str]: h: Dict[str, str] {x-api-key: k, anthropic-version: 2023-06-01} if beta: h[anthropic-beta] beta return h def simulate_bedrock_validation(headers: Dict[str, str]) - None: # Bedrock 网关只接受白名单头 allowed {x-api-key, anthropic-version, content-type} for k in headers: if k anthropic-beta: raise ValueError(400 invalid beta flag) # Bedrock 拒绝 if k not in allowed and k.startswith(anthropic-): raise ValueError(400 invalid beta flag) def main(): direct build_headers(https://api.anthropic.com) print(direct:, direct) # 带 beta直连 OK try: simulate_bedrock_validation(direct) except ValueError as e: print(bedrock ERR:, e) # 400 invalid beta flag if __name__ __main__: main()运行后直连带 beta 正常Bedrock 校验抛400 invalid beta flag与真实 bug 一致。五、解决方案第一层最小直接修复最小修复当后端是 Bedrock 时不发送anthropic-beta头import os from anthropic import AnthropicBedrock client AnthropicBedrock( aws_access_keyos.environ[AWS_ACCESS_KEY_ID], aws_secret_keyos.environ[AWS_SECRET_ACCESS_KEY], aws_regionos.environ[AWS_REGION], # 关键Bedrock 模式不要带 beta 头 ) # 若用底层 requests手动去掉 beta 头 headers {k: v for k, v in headers.items() if k ! anthropic-beta}在 Claude Code 里确保它处于Bedrock 模式通过环境变量或配置指向 Bedrock让它别再附 beta 头某些版本需要在配置里显式关掉预览特性。六、解决方案第二层结构化改进把按后端类型决定头集合抽成策略作为唯一事实来源from dataclasses import dataclass, field from typing import Dict, Optional, Set dataclass(frozenTrue) class ClaudeBedrockBetaFlagPolicy: 按后端类型决定请求头Bedrock 禁止 anthropic-beta。 规则 - 直连 Anthropic可带 anthropic-beta用于开启预览特性 - Bedrock / Vertex移除 anthropic-beta避免 400 invalid beta flag backend: str bedrock # anthropic | bedrock | vertex beta_flags: tuple (prompt-caching-2024-07-31,) def headers(self, api_key: str) - Dict[str, str]: h: Dict[str, str] { x-api-key: api_key, anthropic-version: 2023-06-01, content-type: application/json, } if self.backend anthropic: h[anthropic-beta] ,.join(self.beta_flags) # bedrock / vertex 不加 beta 头 return h def sanitize(self, raw: Dict[str, str]) - Dict[str, str]: # 通用护栏Bedrock 模式下强制剔除 beta 头 if self.backend in (bedrock, vertex): return {k: v for k, v in raw.items() if k ! anthropic-beta} return raw def demo() - None: b ClaudeBedrockBetaFlagPolicy(backendbedrock) print(b.headers(k)) # 无 anthropic-beta assert anthropic-beta not in b.headers(k) a ClaudeBedrockBetaFlagPolicy(backendanthropic) assert anthropic-beta in a.headers(k) if __name__ __main__: demo()七、解决方案第三层断言 / CI 守护import pytest from your_module import ClaudeBedrockBetaFlagPolicy def test_bedrock_has_no_beta_header(): policy ClaudeBedrockBetaFlagPolicy(backendbedrock) assert anthropic-beta not in policy.headers(k) def test_anthropic_keeps_beta_header(): policy ClaudeBedrockBetaFlagPolicy(backendanthropic) assert anthropic-beta in policy.headers(k) def test_sanitize_strips_on_bedrock(): policy ClaudeBedrockBetaFlagPolicy(backendbedrock) sanitized policy.sanitize({x-api-key: k, anthropic-beta: x}) assert anthropic-beta not in sanitized def test_vertex_also_strips_beta(): policy ClaudeBedrockBetaFlagPolicy(backendvertex) assert anthropic-beta not in policy.headers(k)把这些测试加进客户端适配层 CI确保任何 Bedrock/Vertex 路径都不会再发送anthropic-beta。八、排查清单你用的是 Bedrock 还是直连 AnthropicBedrock 不接受anthropic-beta。请求里是否带了anthropic-beta头在 Bedrock 模式下删除它。Claude Code 是否处于 Bedrock 模式确认配置指向 Bedrock 网关。报错是否随启用某预览特性而出现那是 beta 头触发。直连正常、Bedrock 报错基本可锁定是 beta 头差异。是否在 CI 守护了Bedrock 路径不得带 beta 头九、小结通过 Bedrock 调用 Claude 时收到 400 invalid beta flag是因为 Claude Code / SDK 默认携带的anthropic-beta头在 Bedrock 通道不被接受Bedrock 只认自己的头。直连 Anthropic 时这个头合法切到 Bedrock 就成了非法字段。最小修复是 Bedrock 模式下移除anthropic-beta头结构化做法是抽成ClaudeBedrockBetaFlagPolicy按后端类型决定头集合最后用 pytest 锁死Bedrock/Vertex 路径不得带 beta 头避免切换后端时再次踩坑。