ChatGPTClaudeGrok / X / CursorGemini

DeepSeek Harness 工作区全消失:workspaceController unavailable 恢复

故障排查发布于 2026-10-30作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSHworkspaceController工作区会话丢失workspace.jsonprofiles
DeepSeek Harness 更新后项目和会话全不见,新建也报 workspaceController is unavailable。先移出可疑会话目录再谈恢复,按代价从低到高分三步:目录改名、补 workspace.json 字段、修复悬空的 profile 目录联接。

最容易被误判成「数据全丢了」的一次故障,其实是三件完全不同的事共用一个报错:workspace create failed: gateway/service-unavailable: typert gateway: workspace/create: active Service "workspaceController" is unavailable。 看到这句话就重装、回退版本、新建 profile,基本都不会有用——坏数据还在原处。正确的顺序是:先做零成本、可逆的动作,再按代价往上加(#10885)。

DeepSeek Harness 为什么第一步是「移出去」而不是「修回来」

把可疑目录移出 sessions 根是可逆动作:不删、不改内容,只是让启动扫描不再撞上它。做完重启就能知道数据到底还在不在,代价最低。

  1. 完全退出 DSH,包括托盘与任务管理器里的残留进程。
  2. 复制整份 ~/.dsh/sessions 到另一个盘,作为冷备份。
  3. 把所有 *.archived-*、改名过的目录、以及你不确定来源的目录,整体移到 sessions 根之外。
  4. 启动 DSH,看工作区和会话是否回来。
  5. 回来了就说明数据完好,问题只在扫描环节;没回来再往下走第二、第三优先级。

社区案例的实测结果很硬:把被改名的目录移出后,23 个工作区、867 个会话全部重建,零丢失,824 个 v4 与 43 个旧格式会话都能正常解压。

DSH插件 第一优先级:会话目录被原地改名(#10885)

外部工具把会话目录原地改名归档、又在同一位置新建同名目录时,一个 session-id 血统会对应两份目录,启动扫描撞上它就会让整个列表抛错。

  1. 回想有没有外部桥接在管会话,比如飞书机器人。这个案例里是桥接因为 SDK 缺 resume_session,自己做了归档:feishu-<id>/ → feishu-<id>.archived-<ts>/,然后新建一个 <id>/。
  2. 注意「潜伏」这一段:桌面端连续 6 天没重启,而会话只在启动时扫描,所以问题一直没暴露。
  3. 触发点是 rc.2→rc.3 夜间自动更新强制重启,第一次完整扫描就撞上了改名目录。
  4. 失败链路是:JsonlSessionPersistence.assertStoredIdentity() 抛普通 Error(corrupt session log ...: header id ... and cwd identify ...),而 listArtifacts() 只过滤 SessionFormatUnsupportedError 和 SessionPersistenceCorruptionError。
  5. 普通错误逃出去 → 列表抛错 → dsh-workspace 不激活 → workspaceController 不可用。

所以这不是版本问题:社区比对过 rc.2 与 rc.3 的三个相关包,MD5 完全一致,用 rc.2 的命令行对着同一个会话根也能复现同样的报错。

社区在 fork 上给了 12 行补丁(分支 fix/list-survives-relocated-session-logs):列表扫描时(expectedId === undefined)把身份不匹配抛成带类型的 SessionPersistenceCorruptionError,让 listArtifacts 按既有的损坏分支跳过;定向加载仍然抛普通错误。上游未合入。

DeepSeek Harness 第二优先级:workspace.json 通过不了 schema(#10908)

workspace.json 是合法 JSON,但 workspaces 表里任意一条记录缺字段或时间戳不是 ISO 字符串,domain 就打不开,workspaceRegistry 不激活,外壳只显示一个泛化的 service-unavailable。

  1. 完全退出 App,备份 ~/.dsh/storages/workspace.json。
  2. 打开文件,逐条检查 workspaces 表,确认每条都有 path、title、sessionIds、createdAt、updatedAt。
  3. 把时间戳补成 ISO-8601 字符串,例如 2026-01-01T00:00:00.000Z。报错原文就是 createdAt: expected string, received undefined。
  4. 如果确认是废弃记录,直接删掉该条,同时从 global.workspaceIds 里移除对应 id。
  5. 重启 App,单独启动宿主确认 stderr 里不再有 entries did not activate,workspace/create 返回 ok: true。

这一条的迷惑性在于:新建 profile、回退版本、重装都绕不过,因为坏记录仍在同一个 storage 文件里;它也和凭据、HOME、目录权限无关。

DeepSeek插件 第三优先级:profile 根不可达,启动静默退出(#10678)

桌面版双击没窗口、进程直接退出,日志是 ENOENT ... mkdir ...\.dsh\profiles\desktop,那是 withLock 的第一行 mkdirSync 抛出来的,前面没有任何 try。

  1. 先确认 DSH_HOME 是不是一个指向别处的目录联接(比如 G:\deepseek\.dsh 指向 %USERPROFILE%\.dsh)。
  2. 检查联接目标是否还存在:在资源管理器里打开联接路径,悬空的联接列不出内容。
  3. 把之前改名备份的 .dsh.bak 改回 %USERPROFILE%\.dsh,或重建联接指向它。
  4. 再启动。恢复正常说明就是这一条。
  5. 如果本来就不需要这层联接,删掉它、把备份改回原位更省事——多一层联接就多一个失败点。

机制值得记住:recursive: true 的 mkdir 穿过悬空联接时,报的是叶子路径的 ENOENT,不是「联接断了」,所以日志看起来像在抱怨 profiles 目录不存在。

DeepSeek Harness 三种成因怎么分

先看症状形态再动手:报 workspaceController 不可用但窗口能开,查前两条;窗口压根没出来,查第三条。

症状关键证据处理优先级
工作区列表空、新建失败会话根里有 *.archived-* 或改名目录移出目录(第一优先级)
同上,且没有改名目录~/.dsh/storages/workspace.json 字段缺失补 schema(第二优先级)
双击无窗口直接退出日志 ENOENT mkdir profiles\desktop修联接(第三优先级)

DSH插件 恢复之后怎么确认真的好了

别只看窗口里有没有列表,要确认「扫描—激活—增删」三步都通了。

  1. 重启后先数工作区数量,和备份里的目录数量对一遍。
  2. 随便打开一个旧会话,确认历史消息能正常显示、能继续对话。
  3. 新建一个工作区,看是否还会返回 workspace create failed。
  4. 再重启一次,确认状态能保持——如果只在当次进程里正常,说明还有一条坏记录没被移走。

注意事项

  1. 别先删 sessions。社区里有人建议「全部删掉就能用了」,那等于放弃判断机会,先移出、先备份。
  2. 别用新建 profile 试。坏数据在同一个 storage 里,新 profile 读的是同一份。
  3. 别指望回退版本。这条链与版本无关,三个相关包在两个版本间字节一致。
  4. 归档工具要改行为。任何在 sessions/ 里原地改名的外部工具,每个归档周期都会再造一次这个状态。
  5. 重启前先完全退出。多实例会同时扫描,出问题时更难判断是哪一份数据坏的。

如果三步都做完仍然 unavailable,把宿主 stderr 完整抓下来——真实原因不在 UI 那句泛化提示里,只在那份日志里。相关排查见 DeepSeek Harness 会话打不开:turn/end reason 为 null 与重复 id 写坏日志。

ChatGPTClaudeGrok / X / CursorGemini

常见问题

DeepSeek Harness 更新后项目和会话全不见,报 workspaceController is unavailable,数据是不是丢了?

多数情况没丢,DeepSeek Harness 的工作区记录还在原处:社区案例里把被改名的会话目录移出 sessions 根后,23 个工作区、867 个会话全部重建,824 个 v4 加 43 个旧格式都能正常解压。先备份、先移出,再判断。

为什么把可疑会话目录移出去,DeepSeek Harness 的工作区就能恢复?

因为 DeepSeek Harness 只在启动时扫描会话一次,扫描时 assertStoredIdentity() 抛的是普通 Error,而 listArtifacts() 只过滤两种带类型定义的会话错误。普通错误逃出去,列表整体失败,dsh-workspace 不激活,workspaceController 就一直 pending。

workspace.json 是合法 JSON,为什么还会让 DeepSeek Harness 的工作区服务起不来?

合法 JSON 不等于通过 schema,DeepSeek Harness 的 workspace 记录还要过字段校验。workspaces 表里每条记录必须有 path、title、sessionIds、createdAt、updatedAt,时间戳还得是 ISO-8601 字符串;缺一个就抛 DomainError 加 ZodError,domain 打不开,workspaceRegistry 不激活。

回退到旧版本、新建 profile、重装 DeepSeek Harness,能绕过 workspaceController 报错吗?

都不能,回退版本、新建 profile、重装 DeepSeek Harness 都绕不过这个报错。坏记录还在同一个 storage 文件里,新 profile 也会读同一份数据;回退版本更没用,社区比对过 rc.2 与 rc.3 的三个相关包 MD5 完全一致。

桌面版双击后没有窗口直接退出、日志是 ENOENT mkdir .dsh\profiles\desktop,DeepSeek Harness 该怎么处理?

先在 DeepSeek Harness 里看 DSH_HOME 是不是目录联接且目标被改名或移走。withLock 第一行就是 mkdirSync(profile, {recursive:true}),前面没有 try;穿过悬空联接时报的是叶子路径 ENOENT。把备份目录改回原名或重建联接,再启动。

相关术语

workspaceController
workspaceController 是 DeepSeek Harness 桌面端里负责工作区增删查的服务。它依赖 workspaceRegistry 激活,上游任一环节失败时它保持 pending,UI 只会显示 active Service is unavailable。— https://github.com/deepseek-ai/deepseek-harness/discussions/10908
assertStoredIdentity
assertStoredIdentity 是 JsonlSessionPersistence 里校验会话文件头 id 与 cwd 推导路径是否一致的方法。目录被原地改名后它会抛普通 Error,从而绕过 listArtifacts 的类型过滤。— https://github.com/deepseek-ai/deepseek-harness/discussions/10885
workspaceRecord
workspaceRecord 是工作区存储记录的结构,必须包含 path、title、sessionIds、createdAt、updatedAt 五个字段,时间戳为 ISO-8601 字符串。任一条不满足即触发 schema 校验失败。— https://github.com/deepseek-ai/deepseek-harness/discussions/10908
目录联接(junction)
目录联接(junction)是 Windows 上指向另一个目录的重解析点,常被用来把 DSH_HOME 放到别的盘。目标被移动或改名后联接悬空,递归 mkdir 会以叶子路径 ENOENT 失败。— https://github.com/deepseek-ai/deepseek-harness/discussions/10678

来源