【Bug已解决】API Error: 400 invalid beta flag when trying to use Claude Code with Bedrock using claude 3.
【Bug已解决】API Error: 400 invalid beta flag when trying to use Claude Code with Bedrock using claude 3.5 haiku 解决方案
一、现象长什么样
你用 Claude Code(或 anthropic SDK)通过 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", # 直连 OK,Bedrock 报错
}
# 当 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_key=os.environ["AWS_ACCESS_KEY_ID"],
aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"],
aws_region=os.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(frozen=True)
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(backend="bedrock")
print(b.headers("k")) # 无 anthropic-beta
assert "anthropic-beta" not in b.headers("k")
a = ClaudeBedrockBetaFlagPolicy(backend="anthropic")
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(backend="bedrock")
assert "anthropic-beta" not in policy.headers("k")
def test_anthropic_keeps_beta_header():
policy = ClaudeBedrockBetaFlagPolicy(backend="anthropic")
assert "anthropic-beta" in policy.headers("k")
def test_sanitize_strips_on_bedrock():
policy = ClaudeBedrockBetaFlagPolicy(backend="bedrock")
sanitized = policy.sanitize({"x-api-key": "k", "anthropic-beta": "x"})
assert "anthropic-beta" not in sanitized
def test_vertex_also_strips_beta():
policy = ClaudeBedrockBetaFlagPolicy(backend="vertex")
assert "anthropic-beta" not in policy.headers("k")
把这些测试加进客户端适配层 CI,确保任何 Bedrock/Vertex 路径都不会再发送 anthropic-beta。
八、排查清单
- 你用的是 Bedrock 还是直连 Anthropic?Bedrock 不接受
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 头",避免切换后端时再次踩坑。

更多推荐





所有评论(0)