Replies: 1 comment
|
Confirmed at source level and implemented as a cherry-pick-ready branch - same philosophy as #1954: one corrupt artifact must never take down the whole service. Source audit (master 47f9438)
Patch: fix/session-list-isolate-corrupthttps://github.com/zoahdev/deepseek-harness/tree/fix/session-list-isolate-corrupt
Verification
Worth pairing with a doctor |
Uh oh!
There was an error while loading. Please reload this page.
环境
@deepseek-ai/dsh(以及@deepseek-ai/dsh-session-persistence-jsonl、@deepseek-ai/dsh-workspace、@deepseek-ai/dsh-app-boot)—— 均为0.1.0-rc.6com.deepseek.dsh.web,执行dsh web,监听127.0.0.1:3080概要
dsh web无法启动,陷入无限的"崩溃→重启"循环(launchd plist 里配了KeepAlive)。~/.dsh/sessions下单个损坏的会话文件就会让整个进程启动失败,导致整个 Web 服务(以及其它所有会话)都不可访问。launchctl print显示循环在不断加剧:现象
每次拉起进程都以退出码 1 结束。stderr 日志(
~/Library/Logs/deepseek-dsh.error.log)末尾为:根因
dsh-workspace的[cordis.init]调用sessionPersistence.list()来枚举所有会话文件。对每个文件,listArtifacts()读取第一个 Zstandard 帧并用assertZstdHeaderFrame校验。源码位置(
packages/session/session-persistence-jsonl/src/index.ts):约束是:会话文件的第一帧解压后必须恰好是一行、且以
\n结尾。 该校验在启动路径上,单文件失败即整体退出。在出问题的那个文件里,整个会话(header 的 JSON 行加上全部事件行)被写进了单个 Zstandard 帧:
\n在 byte 217,最后一个\n在 byte 38,935 → 多行plaintext.indexOf(0x0A) !== plaintext.length - 1→ 抛错而这个异常是在插件初始化的
list()里抛出的,未被捕获:抛错点不止
assertZstdHeaderFrame一处,readFirstZstdLine(src/index.ts:737)路径上还有:scanZstdFrames(src/zstd.ts):invalid frame magic/reserved frame-header bit/reserved block typedecompressZstdFrame失败 → 包装为header frame failed validation(src/index.ts:762)assertZstdHeaderFrame多行 →first frame is not exactly one header line(src/index.ts:765)这三类都会沿
listArtifacts→list→[cordis.init]一路冒泡,导致整个插件树加载失败、进程退出。由于该文件既没被跳过也没被隔离,下一次KeepAlive重启又撞上同一个文件,再次崩溃——无限循环。影响
dsh进程。对长期运行 / 自动化会话尤其致命——这类服务本应常驻可用。复现步骤
session.jsonl.zstd的第一帧同时包含 header 和若干事件行,或第一帧为空 / 没有结尾换行。~/.dsh/sessions/<projectDir>/<sessionId>/session.jsonl.zstd。dsh web,或 TUI)。KeepAlive的管控下陷入无限崩溃循环。预期行为
单个损坏的会话文件不应拖垮整个服务。持久化层应当把这个坏文件隔离,打一条 warning,然后继续加载其余会话,让 workspace 仍能启动。
建议修复
让
JsonlSessionPersistence.listArtifacts()具备单文件容错能力:在逐文件循环内捕获单文件的校验/解码失败(assertZstdHeaderFrame、首帧解码、非法 magic),将该文件隔离(改名)并continue,使聚合的list()结果只返回有效文件,同时保留对 abort 信号、重复 id、encoding mismatch 等结构性错误的正常抛出。All reactions