Repository navigation
桌面 App 与浏览器助手宿主并存时,对桌面端已打开的会话发消息报 SessionAlreadyOwnedError #112
Description
桌面 App 与浏览器助手宿主并存时,对桌面端已打开的会话发消息报 SessionAlreadyOwnedError
环境
| 项目 | 值 |
|---|---|
| 系统 | macOS(Apple Silicon) |
| dsh-browser | 0.1.4(commit 23895d7,main 最新) |
| DSH runtime | @deepseek-ai/dsh@0.2.0-rc.2(dsh-browser 工作区固定版本) |
| Chrome 扩展 | dsh 浏览器助手 0.1.4 |
| DSH 桌面 App | /Applications/DeepSeek Harness.app |
| DSH_HOME | /Users/<user>/.dsh(桌面 App 与浏览器助手宿主共用同一个) |
复现步骤
- 打开 DSH 桌面 App,打开任意一个工作区会话(例如
~/project-a下的session-XXXX),保持该会话处于打开状态。 -
- 确认浏览器桥宿主已被拉起(
browser-follow-desktop.py会在检测到桌面 App 运行时自动启动它):
- 确认浏览器桥宿主已被拉起(
-
- $ lsof -nP -iTCP:3080 -sTCP:LISTEN
- node 24838 ... TCP 127.0.0.1:3080 (LISTEN)
-
-
- 在 Chrome 里打开 dsh 浏览器助手侧边栏,切换/选中第 1 步那个已在桌面端打开的会话。
-
- 在侧边栏输入任意消息并发送。
实际结果
发送失败,报错:
session "session-2c566034-8fdd-4b06-9b7a-9adaacc4073b" is already owned by an active write handle
期望结果
应该能正常发送;或至少给出可操作的提示(例如"该会话正被桌面 App 占用,是否改为新建会话/只读跟随"),而不是抛出一个底层持久化错误。
补充观察(有助于定位)
- 在侧边栏新建会话可以正常发消息;只有复用桌面端已打开的会话才会失败。
-
- 浏览器助手自己创建的会话(落在
~/.dsh/sessions/--Users-<user>-.dsh-browser-sessions--/)全部无锁,工作正常。
- 浏览器助手自己创建的会话(落在
-
-
- 该问题与 dsh-browser 版本无关:升级到 main 最新(
23895d7)后依然复现。
- 该问题与 dsh-browser 版本无关:升级到 main 最新(
-
证据
1. 报错来自 DSH 的 session 持久化层
错误类型定义在 @deepseek-ai/dsh-session-persistence:
// lib/index.js
var SessionAlreadyOwnedError = class extends Error {
constructor(sessionId) {
super(`session "${sessionId}" is already owned by an active write handle`);
this.name = "SessionAlreadyOwnedError";
}
};实际抛出方是 0.2.0-rc.2 新增的 JSONL 后端 @deepseek-ai/dsh-session-persistence-jsonl。它的设计说明(lib/types/lease.d.ts)写得很明确:
Cross-process write-ownership lock for one session's artifact directory, held for the whole life of a write handle. The arbiter is the kernel: POSIX takes a non-blocking
flock(2)via native system support onsession.lockbeside the log. Contention maps toSessionAlreadyOwnedError.A live but wedged holder keeps the lock until its process exits: there is deliberately no expiry that could expropriate a stalled writer.
也就是说:写所有权是内核级 flock(2),非阻塞、跨进程互斥、无超时抢占。
2. 锁确实被桌面 App 持有(lsof 实测)
$ lsof ~/.dsh/sessions/--Applications-EServer-www-gfh-api--/session-2c566034-.../session.lock
COMMAND PID USER FD TYPE NAME
DeepSeek 24428 user 55w REG .../session-2c566034-.../session.lock
PID 24428 就是 DSH 桌面 App 的主进程:
$ ps -p 24428 -o command=
/Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness --expose-internals .../dsh-desktop-host/lib/index.js ... ~/.dsh/profiles/desktop ...
3. 两个宿主并存,且共用同一个 DSH_HOME
# 桌面 App 宿主(19387)
PID 24428 /Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness ...
# 浏览器桥宿主(3080)—— 由 ~/.dsh/scripts/browser-follow-desktop.py 自动拉起
PID 24838 node ~/.dsh/dsh-browser/node_modules/@deepseek-ai/dsh/lib/bin.js \
web --no-open --host 127.0.0.1 --port 3080
两个进程的 DSH_HOME 都是 /Users/<user>/.dsh,因此共用同一份 sessions/ 目录,必然争抢同一个 session.lock。
4. 冲突链路
① 桌面 App 打开会话 X → PID 24428 取得 X/session.lock(内核 flock 独占)
↓
② 浏览器侧边栏对会话 X 发消息
↓
③ 扩展 → 3080 宿主(PID 24838)请求对 X 开写句柄
↓
④ 内核 flock 已被 24428 独占,且官方"故意不做超时抢占"
↓
⑤ SessionAlreadyOwnedError ✗
根因判断
dsh-browser 的架构前提是「再起一个全功能 DSH 宿主,并与桌面 App 共享同一个 DSH_HOME」——scripts/browser-follow-desktop.py 的存在正说明这是有意设计。
在 DSH 0.1.x 时代,写所有权只在进程内记账,两个宿主各写各的,虽然不严谨但"能用"。DSH 0.2.0-rc.2 换成了内核级跨进程 flock 后,这个前提就破产了:任何被桌面 App 打开的会话,浏览器侧边栏都无法再取得写句柄。
这不是 DSH 的 bug(跨进程锁是必要的加固),而是 dsh-browser 在这个新约束下缺少冲突处理。
- 该问题与
~/.dsh/browser-extension/、~/.dsh/dsh-browser/的重新安装无关:清空重装后同样复现。 -
- 与本仓库现有 issue(Snapshot: payment fields with multi-token autocomplete are echoed unmasked #109 / Bridge: any installed extension can connect without the token via a chrome-extension:// Origin #108 / 远程 --host 0.0.0.0 部署无法连接:connect-src 是固定 origin 列表,且 /ext/bridge-config 硬编码回环地址 #97 / Edge 153(Chromium 142+ Local Network Access)下侧边栏无法自动发现桥:/ext/bridge-config 缺 CORS 头 #96 / 增加对新DSH版本的支持 #93 / 【建议】是否考虑加入对Edge的支持? #83 / bug #78 / 【建议】能否支持悬停下拉菜单与点击任意位置(hover / 坐标点击)? #75)均不重复。
-
Activity
Lum1104 commentedon Oct 7, 2026
感谢反馈!
jeavenguitar commentedon Oct 7, 2026
不客气,希望能修复这个问题
graydovee commentedon Oct 17, 2026
这不是 dsh-browser 的缺陷,而是「两个 dsh 宿主共用同一个 DSH_HOME」时的使用问题。
dsh 0.2.x 起,会话的写所有权是内核级、按会话、跨进程独占,且有意不做超时抢占(POSIX flock / Windows 具名信号量)。桌面 App 的宿主打开会话 X 时持有 X 的写句柄;此时再起一个共用
~/.dsh的dsh web,第二个宿主对 X 只能读不能写,于是报SessionAlreadyOwnedError。两个dsh web之间也是同样情况。新建会话不受影响,是因为它由第二个宿主自己创建、自己持有。正确做法:不要为了浏览器面板再起一个宿主,让侧栏直接连桌面 App 的宿主即可。
之前你额外起一个3080端口的web,可能因为桌面端的本地端口每次启动都随机、面板探不到。这一点已经在 PR #121 的最新提交里解决:现在面板打开时能扫描端口自动发现桌面宿主。