DeepSeek Harness headless 报 MISSING_CREDENTIAL:凭据查找顺序与配置
密钥就在 ~/.dsh/.credentials.yaml 的 refs 里,值也是内联的真实 key,可 dsh --profile headless "hi" 一秒就退,报 MISSING_CREDENTIAL: llm-pi-ai: no credential for provider route "zai-coding-cn"。 这不是密钥写错了,而是从 0.2.1-alpha.3 起,随包的 headless profile 根本不再挂载凭据服务——它换了整套来源(#11051)。先判环境,再判版本,最后选路径。
DeepSeek Harness 第一步:判环境,桌面端正常不代表 headless 正常
桌面端读凭据库,headless 不读;同一个 key 在两边命运完全不同,先确认你跑的是哪一种。
- 看启动命令:带
--profile headless、或以dsh headless形式被调度器拉起的,就是 headless。 - 看有没有界面:桌面端有 Web UI 和「模型」设置页,headless 只有 stdout 与 NDJSON。
- 看报错格式:headless 是
dsh: <CODE>: ...一行就退,桌面端会在 UI 里给卡片。 - 如果你在调度器或 CI 里跑,基本可以按 headless 处理。
这一步的结论只有一个:不要把桌面端「在模型页填了 key 就能用」的经验搬到 headless。
DSH插件 第二步:判版本,0.2.1-alpha.3 是分水岭
这是文档化的设计变更,不是回归:0.2.0-rc.2 能解析存储凭据,0.2.1-alpha.3 起随包 headless profile 禁用了相关服务。
- 执行
dsh --version记录完整版本号。 - 低于 0.2.1-alpha.3 的,先按旧行为排查。
- 0.2.1-alpha.3 及之后,直接判定为「存储不生效」,别再花时间验证
.credentials.yaml的格式。 - 顺带看一次 profile 的
cordis.patch.yml,里面明确列着 credentials、authorization、deepseek-account 三项为禁用。
社区还观察到 0.2.1 首次 headless 启动会把 .credentials.yaml 重写成 refs/records 结构,所以文件 mtime 变了并不代表你改对了地方。
DeepSeek Harness headless 的凭据查找顺序:只有三处
启动环境 → 调用目录的 .env → Harness home 的 .env,仅此三处;凭据库不在其中。
- 第一优先是进程环境变量,也就是你启动那一刻的
env。 - 第二是当前工作目录下的
.env。 - 第三是
~/.dsh/.env(或DSH_HOME对应的.env)。 - 三处都没有,才抛
MISSING_CREDENTIAL,且失败发生在联系模型端点之前——所以网络、代理、余额都不是原因。
# ~/.dsh/.env(变量名以 profile 的 refs 为准)
ZAI_CODING_CN_API_KEY=sk-xxxxxxxx
社区做过隔离对照:只有存储 key 的 headless 完全不发请求;导出假 key、调用目录 .env、home .env、三行补丁这四种方式都能跑通,mock 也收到了对应 key。对照组里 SDK 与 ACP 只用存储 key 也能通,因为它们的凭据服务是活跃的。
DeepSeek插件 两条可执行路径:写 .env 或恢复服务
最省事的是把 key 写进 ~/.dsh/.env;想继续用凭据库,就按 README 的三行补丁把服务加回来。
- 路径 A:在
~/.dsh/.env里写一行ZAI_CODING_CN_API_KEY=<真实 key>,注意变量名要与 profile 里refs引用的一致。 - 确认文件权限收紧,别留成全局可读。
- 重新执行
dsh --profile headless "hi",看是否不再报MISSING_CREDENTIAL。 - 路径 B:打开
packages/bundle/headless/README.md,把文档里的三行恢复补丁加到你的 profile 配置里。 - 重启后再跑一次,验证凭据从存储解析成功。
- 如果用调度器(例如 LaunchAgent),记得把 key 写进它的
EnvironmentVariables,否则交互式终端能跑、定时任务仍然失败。
社区案例里生产定时任务就是在 10-23 的 07:30 与 09:00 两次失败,最后靠注入调度器环境变量恢复。
DeepSeek Harness 提示文案本身会误导你
MISSING_CREDENTIAL 的文案不区分 plane:它先推荐「存到凭据服务(Web 模型页会写进去)」,而 headless 恰恰不挂载这个服务。
- 看源码就知道:解析器先
ctx.get('credentials')判断服务在不在,再决定查存储还是查启动环境。 - 但错误文本是三段拼死的,不随这个判断变化。
- 结果就是用户照着第一条建议操作,再撞一次同样的错。
- 真正有效的是第三句「在启动环境里 export」——社区指出这一句本来就在,只是被前两句盖住了。
- 这条属于诊断文案缺陷,影响级别不高,但不是「凭据丢失」,也没有越权风险。
DSH插件 附带场景:全局吊销浏览器会话令牌
桌面 Web 端的浏览器 cookie 能跨普通重启存活,要全局吊销只能删 client-connection/browser-session 这一条记录再重启。
- 完全停止所有使用同一 home 的 Harness 进程。
- 备份
.credentials.yaml(默认%USERPROFILE%\.dsh\.credentials.yaml;改了DSH_HOME就用实际路径)。 - 在
records下只删除client-connection/browser-session键和它的整个值,保留version、refs与其他 records;如果它是最后一条,留records: {}。 - 重启 Harness,用新生成的启动 URL 重新登录。
- 验证:用旧 cookie、去掉
?token=、保持相同 scheme/host/port 请求,应返回 401。 - 再用新启动 URL 请求应返回 303,其新 cookie 认证应返回 200。
这里有个坑:authority 必须完全一致。换了主机名或端口,cookie 本来就会失效,你会误以为吊销成功了。社区在隔离环境里验证过:普通重启旧 cookie 仍有效,删掉那条记录再重启才被拒。
注意事项
- 别只改
.credentials.yaml就期待 headless 生效。它读的是.env与环境变量。 - 别把 SDK / ACP 的表现当参照。它们的凭据服务是活跃的,提示对它们适用。
- 别忽略调度器环境。交互式终端能跑不等于定时任务能跑。
- 吊销令牌别删整份凭据文件。只删那一条记录,其他引用不受影响。
- 记录版本号。这是判断「设计变更还是缺陷」的唯一依据。
如果你的报错码不是 MISSING_CREDENTIAL 而是 401/403,那是另一条链路,先查凭据内容与账号状态。相关排查见 DeepSeek Harness 配置 API Key 报错:MISSING_CREDENTIAL 与 UNKNOWN_MODEL 的排查与解决。
常见问题
因为 DeepSeek Harness 随包的 headless profile 把 credentials、authorization、deepseek-account 三个服务都禁用了,存储型凭据根本不会被读。它只查启动环境、调用目录的 .env 和 ~/.dsh/.env,所以把 key 放进 ~/.dsh/.env 才有效。
DeepSeek Harness 的这个分界是 0.2.1-alpha.3,按社区回复是文档化的变更,不是回归。0.2.0-rc.2 上同样的配置能解析成功,升级后就只剩启动环境这一条路。
因为 DeepSeek Harness 的提示文案没有按 plane 分支。代码里已经用 ctx.get('credentials') 判断服务在不在,文案却还在推荐一个 headless 没挂载的服务;真正有效的第三句是「在启动环境里 export」。
按 DeepSeek Harness 随包的 packages/bundle/headless/README.md 里的三行补丁把凭据相关服务加回来。社区核对的可行来源有四个:export 环境变量、调用目录 .env、~/.dsh/.env、三行恢复补丁。
先停掉所有 DeepSeek Harness 进程,备份 .credentials.yaml,在 records 下只删 client-connection/browser-session,再重启。之后用旧 cookie 但去掉 ?token= 请求同一 authority,应返回 401。
相关术语
- MISSING_CREDENTIAL
- MISSING_CREDENTIAL 是 DeepSeek Harness 在解析不到模型凭据时返回的错误码,headless 下会以 exit 1 秒败。它表示凭据来源在当前组合里不可用,而不是密钥内容错误。— https://github.com/deepseek-ai/deepseek-harness/discussions/11051
- headless profile
- headless profile 是 DeepSeek Harness 随包提供的无界面运行 profile,其 cordis.patch.yml 默认禁用 credentials、authorization 与 deepseek-account 三个服务。凭据只能来自启动环境或 .env 文件。— https://github.com/deepseek-ai/deepseek-harness/discussions/10609
- launch environment
- launch environment 是启动 dsh 进程时继承的环境变量集合,是 headless 下优先级最高的凭据来源。它排在调用目录 .env 与 Harness home .env 之前。— https://github.com/deepseek-ai/deepseek-harness/discussions/10609
- client-connection/browser-session
- client-connection/browser-session 是本地凭据库中保存浏览器会话令牌的记录键。删除该记录并重启可全局吊销已发放的会话 cookie,其他凭据记录不受影响。— https://github.com/deepseek-ai/deepseek-harness/discussions/10915
来源
- #11051 — headless: credentials refs resolution broken(MISSING_CREDENTIAL)· deepseek-ai(GitHub Discussions)
- #10609 — fix(headless): missing-key diagnostic recommends an ignored credential store· deepseek-ai(GitHub Discussions)
- #10915 — Supported browser-session revocation procedure for Harness 0.2.1-rc.2· deepseek-ai(GitHub Discussions)
- deepseek-ai/deepseek-harness(源码仓库)· GitHub