OpenHands Agent Canvas 中 Claude Code 同时设置 ANTHROPIC_BASE_URL 与 OAuth Token 导致认证失效怎么排查?
在 Agent Canvas 中以 ACP agent 方式使用 Claude Code、通过 Pro/Max OAuth token(CLAUDE_CODE_OAUTH_TOKEN)完成认证时,如果后端的 global secrets 里同时存在一个 ANTHROPIC_BASE_URL——比如从 LiteLLM 继承来的 base URL——token 的 bearer auth 会静默失效。ACP agents 使用文档对这一组合的表述是:inherited LiteLLM base URL 会 "silently break the token's bearer auth (it routes the request away from Anthropic)"。本文按项目文档给出的机制,说明如何在界面上确认两个值同时存在、如何移除冲突项,以及修复后如何验证。
为什么这个组合同时会破坏认证
三个事实叠加构成了根因(详见 ACP agents 使用文档 的 Authentication 与 Docker 两节):
- 保存的 secret 会随每次启动请求一起下发。 你在 Canvas 填入的每个凭据都会被保存为一个 global secret,secret 名与 Agent Server 导出到 ACP 子进程的环境变量名完全一致(如
ANTHROPIC_API_KEY)。你自己保存的 base URL 会像其他保存的 secret 一样,"rides along on every start request"。 - base URL 是"登录优先"规则中的例外。 正常情况下 subscription / OAuth 登录优先于 API key——已登录时环境里的 key 不会被使用;但
*_BASE_URL不同,一个自定义值会把 CLI 指向别的端点(代理或网关),并且 does take effect even under a login。当这个端点不是 Anthropic 本身时,OAuth token 的 bearer auth 就被路由到错误的位置而失效。 - Canvas 不会从你的 LLM settings 派生 base URL secret——secret 列表里的
ANTHROPIC_BASE_URL只能来自你手动保存,这也是排查的切入点:它一定有你保存过的记录。
冲突对在代码中的定义位于 src/constants/acp-providers.ts:CLAUDE_CODE_OAUTH_TOKEN 与 ANTHROPIC_BASE_URL、ANTHROPIC_API_KEY 各构成一对冲突。该文件注释同时说明:OAuth token 被设置时,SDK 会剥除这两个冲突变量,即"alongside the token"设置的值 "is silently ignored at runtime"。文档与代码对机制的表述略有差异,但结论一致——两个值无法同时正确工作,且文档的处置建议是统一的:leave one of them blank。
第一步:确认两个值都已设置
两种只读检查方式,任选其一即可定位问题:
在凭据表单中找冲突警告。 表单有两个入口:onboarding 的 "Set up credentials" 步骤,以及 Settings → Agent 的 Credentials 区块,两者渲染同一个警告组件(acp-conflict-warnings.tsx)。当 preset 为 Claude Code 且 CLAUDE_CODE_OAUTH_TOKEN 与 ANTHROPIC_BASE_URL 同时有值时,表单显示:
Setting ANTHROPIC_BASE_URL alongside CLAUDE_CODE_OAUTH_TOKEN breaks its authentication — leave one of them blank.
警告的触发条件是"本次输入 或 已保存":即使你现在没有填写任何字段,只要之前保存过 ANTHROPIC_BASE_URL secret,警告依然会出现。反之,如果警告没有出现,说明两个值目前至多只有一个存在,可继续到 Secrets 列表核对。
直接查看 Secrets 列表。 在 Settings → Secrets 中检查是否存在名为 CLAUDE_CODE_OAUTH_TOKEN、ANTHROPIC_BASE_URL 的条目(顺带核对 ANTHROPIC_API_KEY——它与 OAuth token 同样构成冲突对,也会触发警告)。文档明确:onboarding 里保存 secret 与在 Settings → Secrets 中新增完全等价,这里可以随时编辑或删除。
第二步:移除 ANTHROPIC_BASE_URL
文档将 base URL 定位为 "an advanced override, not needed for normal use",并给出明确指令:Only set it deliberately, and not with the OAuth path。 因此对 OAuth token 路径,修复动作是:
- 在 Settings → Secrets 中找到名为
ANTHROPIC_BASE_URL的 secret,删除(或将其值清空)后保存。 - 如果你的环境确实需要把 CLI 指向代理/网关端点,文档支持的搭配是 API key 路径:三个 ACP provider 的 onboarding 都收集 "API key (+ optional base URL)",即
ANTHROPIC_API_KEY配 base URL,此时不要再保留CLAUDE_CODE_OAUTH_TOKEN(两者同样构成冲突对,且订阅登录生效期间环境中的 key 不会被使用)。
不要试图用 CLAUDE_CONFIG_DIR 绕过此问题:文档明确说明它只移动 Claude Code 的配置目录(settings/history,不是 token),登录检测不依赖它,移动它对修复认证无效。
第三步:验证修复
凭据值是在 ACP 子进程 spawn 时由 agent-server 从 secret store 解析回来的(start request 以 LookupSecret 引用,spawn 时 resolve),所以移除 secret 只对新启动的会话生效——running conversation 保持它开始时使用的配置。验证顺序:
- 冲突警告消失。 重新打开 onboarding 凭据步骤或 Settings → Agent 的 Credentials 区块:
CLAUDE_CODE_OAUTH_TOKEN有值、ANTHROPIC_BASE_URL留空时,上文的警告不再出现。若 login probe 探测到已有会话,该步骤还会显示 "you're already signed in" banner 且保持可跳过。 - 本地后端核对登录状态。 当 Agent Server 与 Claude Code 的订阅登录运行在同一台机器上(macOS Keychain,或 Linux 的
~/.claude/.credentials.json)时,文档给出的核对方式是用claude auth status:订阅登录与 key 同时存在时,它应报告 authenticated via the subscription(claude.ai),而不是 key。 - Docker / 云后端的边界。 按 容器化示例说明,login probe 检查的是 CLI 登录状态(
claude auth status/ 凭据文件),不检查容器环境变量——一个只烘焙了CLAUDE_CODE_OAUTH_TOKEN的容器通常仍会 probe 为 logged-out,onboarding 可能仍要求你在 UI 中(重新)录入凭据才能继续;已保存的凭据对 agent 本身仍然有效。容器化后端上凭据步骤是必做的(没有 host login 可回退),本地后端则所有字段可选、步骤可跳过。
相关边界
ANTHROPIC_BASE_URL在表单中按纯文本渲染而非 secret,单独存在时不满足必选凭据步骤——所以它不会把区块标记为 "credentials configured",但它仍会随每次 start 请求下发,这正是排查时必须显式检查它的原因。- 修复前若已有会话在用旧值运行,无需重启容器,只需在移除 secret 后新开一个会话即可走干净的凭据解析。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00