deepseek harness 在 UOS 下报 invalid-time-zone 的排查与修复
问题现象
启动 dsh web(@deepseek-ai/dsh)后,浏览器访问 http://127.0.0.1:3080 新建会话并提交消息,对话框返回错误:
1 | clientTimeZone must be UTC or a valid IANA Area/Location name |
服务端响应 { ok: false, error: { code: "invalid-time-zone", details: { value: "Asia/Beijing" } } }。
API 直连复现:
| clientTimeZone | 结果 |
|---|---|
Asia/Beijing |
invalid-time-zone |
Asia/Shanghai |
OK |
原因分析
请求链路
1 | 浏览器 → POST /api/session.prompt → canonicalClientTimeZone() 校验 → Agent |
客户端取时区
dsh-client-runtime/lib/client.js:7009:
1 | function resolvedClientTimeZone() { |
浏览器从 OS 读取时区。本机 /etc/timezone = Asia/Beijing,所以浏览器上报 "Asia/Beijing"。
服务端校验
dsh-host-apiproxy/lib/types/api-proxy.js:115-134:
1 | const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/; |
校验两关:
- 字面必须为
"UTC"或匹配 IANA Area/Location 正则(必须含/)。 Intl.DateTimeFormat({ timeZone })必须接受,并且resolvedOptions().timeZone回写也通过同样校验。
根因:ICU 78 移除了 Asia/Beijing 别名
| 项 | 值 |
|---|---|
| Node | v22.23.2 |
| ICU | 78.2 |
| 支持的时区数 | 418 |
1 | $ node -e 'console.log(Intl.supportedValuesOf("timeZone").filter(z => z.startsWith("Asia/")).length)' |
服务端 ICU 78 不再认识 Asia/Beijing,于是 Intl.DateTimeFormat({ timeZone: 'Asia/Beijing' }) 抛错,canonicalClientTimeZone 返回 undefined,最终被映射成 invalid-time-zone。
注意:/usr/share/zoneinfo/Asia/Beijing 与 /Asia/Shanghai 是同一文件的两个软链(都指向 ../PRC),系统层面行为完全等价,仅名字在 ICU 列表中已被规范化。
解决方法
根本修复:改系统时区
把已被 ICU 移除的 Asia/Beijing 改为仍受支持的 Asia/Shanghai(二者指向同一 tzdata 文件,行为等价):
1 | sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime |
然后重启浏览器(让浏览器重新读取系统时区),刷新 http://127.0.0.1:3080 再提交即可。
临时方案(不动系统时区)
Chrome DevTools → ⋮ → More tools → Sensors → Override timezone 选 Asia/Shanghai。仅对当前 tab 生效,刷新或新开 tab 即失效。
其他常见易踩坑的非法值
服务端正则 ^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$ 要求 Area/Location 形式,以下值都会被拒绝:
| 输入 | 结果 | 原因 |
|---|---|---|
"" |
拒绝 | 空 |
" Asia/Shanghai " |
拒绝 | 首尾空白 |
"CST" |
拒绝 | 缩写,无 / |
"GMT+8" |
拒绝 | 偏移写法,无 / |
"+08:00" |
拒绝 | 偏移写法,无 / |
经验小结
- Web 应用跨 ICU/浏览器上报时区时,系统时区字符串与 ICU canonical name 不一致 是常见坑。
- 本机 OS 虽保留
Asia/Beijing的 tzdata 别名(指向 PRC),但运行时的 ICU 已统一为Asia/Shanghai。 - 排查类似
invalid-time-zone类问题,先在 Node 端跑一次Intl.supportedValuesOf("timeZone")看是否包含浏览器上报值,能快速定位。