Repository navigation
--port 0 causes unbounded dsh-auth-* cookie growth -> HTTP 431 startup failure
#12360
Replies: 6 comments
|
强烈要求可以变更随机端口 ① 先看现状(客户端开着也能跑,只会告诉你读不到) ② 完全退出客户端:托盘图标 → 退出,并确认进程列表已无 DeepSeek Harness ③ 清理(先看会删几条,再真删) |
|
我这边采用的规避方案(供参考)
先确认这个问题确实存在:我按你给出的因果链复现过。`--port 0` 让每次启动都会换端口,于是 Chromium 按 host 而不是按端口隔离 cookie,导致 `dsh-auth-127.0.0.1` 只增不减;累积到几十条以后,Cookie 请求头超过 Node 默认的 `maxHeaderSize`,服务器返回 431,最终表现为 `Web authentication failed`。
我实际使用的方案:由启动器做兜底清理
我没有安装官方插件,而是在 DSH 安装目录里放置了两个文件,启动时自动执行:
**1. `start-dsh.ps1`**:启动前先检查 DSH 是否已经在运行:
- 如果什么都没有:先清理 cookie,再启动 DSH。
- 如果有窗口:用 `SetForegroundWindow` 激活已有窗口,然后执行 `exit 0`,不重复启动;
- 如果有进程但没有窗口:记录日志后执行 `exit 0`,等它自己完成启动;
**2. `dsh-cookies.js`**:用 `better-sqlite3` 直接打开 Cookie 库,然后执行:
```sql
DELETE FROM cookies WHERE name LIKE 'dsh-auth-%';
```
这段清理只在确认没有任何 `DeepSeek Harness` 进程运行时才执行;否则库会被 Chromium 独占,无法打开。
### 实测日志
```
2026-11-06 16:04:56 cookie prune: {"before":1,"removed":1,"after":0}
2026-11-06 16:05:59 DSH already running; skipping cookie prune
2026-11-06 16:14:34 DSH already running; existing window activated
```
目前 Cookie 库大小为 20,480 字节,`dsh-auth-*` 只剩 1 条,远低于触发 431 的阈值。
### 两个容易出错的地方
1. **清理必须在客户端完全退出之后执行。** Chromium 运行期间会独占 Cookie 库,因此清理程序只能报「无法打开」。
2. **要检查启动路径有没有绕过启动脚本。** 我一开始就遇到了这个问题:任务栏快捷方式直接指向 `DeepSeek Harness.exe`,导致清理逻辑完全没有执行;后来把 `.lnk` 的 Target 改成通过启动脚本启动,才恢复正常。Windows 桌面端可能也有同样的问题。
### 对 `dsh-cookie-cleaner` 的两点建议
1. 增加一个 `--port <固定端口>` 的包装启动选项,这样能同时解决多实例端口漂移的问题。
2. 清理时输出「库路径 + 剩余条数 + 各 cookie 的 domain」,方便判断是不是真的在按 host 累积。
根治方案还是要支持固定端口或可配置端口;如果每次启动都随机分配端口,那么任何依赖 cookie 或 localStorage 的客户端侧状态都会持续累积。
zyn94264
***@***.***
|
|
Checked this against current What master already has. What was still wrong. The call was fire-and-forget: void removeLegacyHostCookies(...).catch(...)so the welcome backend connection and the page load proceeded while the prune was still running; any request in that window can still carry the stale Cookie header. Patch — branch https://github.com/aturzone/deepseek-harness/tree/fix/desktop-cookie-cleanup-order It awaits the prune before the boot continues, keeps the failure non-blocking (logged, boot proceeds), and adds an ordering regression: with the former What would settle the remaining question ( On the secondary damage ("disable third-party plugins" overwrote |
|
补充一份独立复现(同一根因),侧重补两个可核对的点:本机这个 build 里没有 cookie 清理,且这些 Cookie 落在默认会话(正好回答上面关于 defaultSession vs partition 的疑问)。 环境
崩溃日志实测数据
代码 / 版本核对(回应上面 aturzone 的说明)
临时规避完全退出客户端后删除 建议
(本机路径已脱敏,未附任何凭证。) |
|
你好,
感谢这几轮补充。我按你给的两条线索(defaultSession 还是 partition、以及 `.bak-<时间戳>` 的行为)在本地做了核对,另外把「预设丢失」这条链也一并整理了出来,可能对你定位产品侧问题有帮助。
## 一、关于 cookie 累积
你提到的两处代码锚点,我都从安装包里的 `lib\main.js`(21,420 行)提取核对过,和你说的一致:
- 第 16856 行:`if (!authenticated.ok) throw new Error("desktop welcome: Web authentication failed");` —— 就是崩溃日志里的抛出点。
- 第 20386 行:`welcomeBackend = await connectDesktopWelcome(ready.url, (input, init) => net.fetch(input, init), async () => (await session.defaultSession.cookies.get({ url: ready.url })).map(...)` —— 确认 welcome 走的是 `session.defaultSession.cookies`。
另外整个 `main.js` 里 `removeLegacyHostCookies` 出现 **0 次**,`defaultSession.cookies` 只出现 1 次,就是上面那一处。所以「装的 build 早于该 mitigation」在本地成立。
partition 方向也查了:这台机器只有一个 partition store,`Partitions\dsh-platform-c6c84f580c3ce8182beae72cadffd6eb595ba54c55e1c409d47e2333c4524b6f\Network\Cookies`。用共享读模式复制出来查询,**总行数 0,`dsh-auth-*` 也是 0**。所以至少这个 profile 的陈旧 cookie 不在 partition 里。
默认库 `Network\Cookies` 在客户端运行时被 Chromium 独占,复制直接失败(提示文件正被另一进程使用),所以条数暂时给不了。冷退出后我会补上:总行数、`dsh-auth-*` 的条数与不同端口数,以及连续两次「启动 + 清理」之后条数是否收敛。
## 二、关于 patch 被改名成 `.bak-<时间戳>`
这条我确认跟你描述一致,而且能补一个精确时间点。
本地留下了 `cordis.patch.yml.bak-1793874519559`,35.5KB。把文件名里的时间戳换算出来是 **2026-11-05 18:28:39**。当前生效的 `cordis.patch.yml` 是之后重建的,34.9KB。
用户侧看到的「配置被清空」,实际是「原文件被整份改名 + 一份新文件顶上来」,两个文件都在磁盘上,但界面上没有任何提示。你的判断是对的:缺的是产品化提示,不是校验。
## 三、预设消失是三层原因叠加
**第一层,patch 被改名。** `preset-java`、`preset-redteam` 这些声明原本手写在 `cordis.patch.yml` 里,文件被改名之后,新 patch 里没有这些行,预设自然不再注册。
**第二层,预设源目录缺失。** `<DSH_HOME>\.agent-presets\` 当时只剩 `java` 一个目录,`redteam` 目录整个不存在。而 ***@***.***/dsh-agent-preset` 是从 `.agent-presets\<id>\` 下读 `agent.cordis.yml` 和 `preset.yml` 的,目录不在,patch 里就算恢复了声明也加载不出来。
**第三层,预设里引用了新版本已移除的子插件。** `redteam` 的 `agent.cordis.yml` 第 296-298 行声明了:
```yaml
- id: tool-subagent-list-agents
name: ***@***.***/dsh-tool-subagent-control/list-agents'
```
但 0.2.2-rc.1 的 ***@***.***/dsh-tool-subagent-control` 包,`exports` 只有 `.`、`./src/*`、`./package.json`、`./locale/*.json`,**没有 `./list-agents`**。这个子插件永远启动不了,整个预设就落成 `registered-broken`。`D:\dsh-data\dsh-home\redteam\preset-declare.json` 里写得很直接:
```json
{
"ok": false,
"phase": "registered-broken",
"id": "redteam",
"plugins": 19,
"broken": "tool-subagent-list-agents ***@***.***/dsh-tool-subagent-control/list-agents): never started"
}
```
`java` 预设里也有完全相同的一行,同样会 broken。
## 四、版本升级后预设的写入方式变了
这一条是我这次判断错的地方,可能对文档或编辑器提示有用。
旧习惯是直接把预设写成顶层条目:
```yaml
- id: preset-java
name: ***@***.***/dsh-agent-preset'
config: { id: java, ... }
```
在当前版本里,这样写**不报错,也不生效**。从 `dsh-app-boot/lib/index.js` 核对到的行为:
- `L499`:`if (patch.insert) ensureIds(patch.insert, used);` —— `insert` 合法,语义是「往已有条目后追加」;
- `L517`:`const { id, insert, name, ...overrides } = patch;` —— 顶层条目走覆盖分支;
- `L537`:`warn("patch: id is required for non-insert patches")` —— 顶层条目要求 `id` 在既有插件树里存在,否则跳过,只留一条 warn。
所以新版本必须写成:
```yaml
- insert:
- id: preset-java
name: ***@***.***/dsh-agent-preset'
config:
id: java
order: 10
plugins: [...]
```
目录结构也变了:现在是 `<DSH_HOME>/.agent-presets/<id>/agent.cordis.yml` + `preset.yml` 两件套,插件列表在 `agent.cordis.yml` 的 `config.plugins` 下,persona 也在同一个文件。旧版可能只有一段 patch 声明,升级后照旧习惯写就会「声明还在、加载不出来」。
## 五、建议
1. **预设注册失败要可见。** `registered-broken` 的预设现在会被模式下拉静默过滤。至少保留一条灰色项,标出 broken 的子插件名,别让用户以为「预设被删了」。
2. **`.bak-<时间戳>` 要提示。** 改名后下一次启动给一条通知,写明备份文件名和「有 N 行手写配置(预设/MCP)未恢复」。现在这个信息只存在于文件系统里。
3. **顶层 `- id:` 找不到既有条目时要有界面错误。** 目前只有控制台 warn,用户完全看不到,排查成本很高。
4. **`insert` 与覆盖语义的差异写进文档或内联提示。** 这次就是照旧习惯写顶层,把 Java 模式写没了。
5. **清理顺序按你那个分支来即可。** 不管 defaultSession 还是 partition 是持有方,先 `await` 清理再握手都是对的;将来若有 partition 持有 cookie,prune 需要遍历已创建的 session。
补充数据出来后我再回一条。
zyn94264
***@***.***
|
|
根本就是应该开放自定义端口范围不要随机飘端口 |
Uh oh!
There was an error while loading. Please reload this page.
Symptom
DSH Desktop fails to start: the window shows
web authentication failed, and the host returns HTTP 431 (Request Header Fields Too Large). Rolling back to the previous version does not help.Root cause chain
dsh-desktop-host/lib/index.js:453launches with--port 0, so a random port is used on every start.127.0.0.1), not by port.dsh-auth-<authority>cookie; old ones are never pruned.dsh-auth-*cookies accumulate and theCookierequest header reaches 16,188 bytes.maxHeaderSizeis 16,384 bytes; once exceeded, the host rejects the request with 431 and authentication fails.Secondary damage
During the same recovery flow, the desktop "disable third-party plugins" path overwrote the 36 KB
cordis.patch.ymlwith[](backup:cordis.patch.yml.bak-1793874519559).Environment
%APPDATA%\@deepseek-ai\dsh-desktop\logs, 3 entries (18:28:43, 18:29:47, 18:30:48)Suggested fixes
--port 0, so cookies do not accumulate per host.dsh-auth-*cookies on startup.maxHeaderSize/ use a non-cookie session token.All reactions