DeepSeek Harness 文件工具异常:写文件权限 0600、SSHFS 写失败与大文件卡死

故障排查发布于 2026-10-17作者: DeepSeek Plugin 插件市场
DeepSeek Harnesswrite 工具edit 工具0600SSHFSCannot mix BigIntglobdiff 卡死
DeepSeek Harness 文件工具有一组固定故障:新建文件恒为 0600 且无视 umask、SSHFS 挂载盘上 mkdir 报 EPERM 让写全失败、大文件覆盖写把宿主主线程冻住约 8 秒,另含 app.asar 抛 Cannot mix BigInt、glob 丢结果。本文逐个给出判据与处置。

DeepSeek Harness(DSH)的文件工具看起来最稳,但它的故障都藏在「文件系统差异」与「极值场景」里:POSIX 上 write 新建的文件恒为 0600(无视 umask、还钉住目录默认 ACL);放到 SSHFS/WinFsp 挂载盘上 mkdir -p 会返回 EPERM,导致写与编辑全不可用;打包(asar)形态下探测 app.asar 内路径会因数值与 BigInt 混算抛错,让整个文件系统技能提供者被跳过(表现为技能目录整块为空);而一次几千行的覆盖写会让结果卡片的差异计算在宿主主线程上同步跑满,冻住约 8 秒。 除这些之外还有三处更细的坑:glob 在权限墙下把已扫到的结果整单作废、edit 的重叠匹配被当成唯一目标而误改文件、以及快照把精确整数变成对象。本文按「写 → 编辑 → 搜索 → 打包 → 大文件」分段给出判据与处置(#9292、#9376、#9189、#9371、#9364、#8978、#9506)。

DeepSeek Harness 写:新建文件恒 0600、挂载盘写不了

DeepSeek Harness 的 write 工具在这里有两处固定故障:新建文件恒为 0600、目录默认 ACL 也被钉住,以及 SSHFS/WinFsp 挂载盘上 mkdir 报 EPERM 让写与编辑整体不可用。

DeepSeek Harness 新建文件权限恒为 0600

一句话结论:新建文件这条分支只应用了内部的保护模式,而「按传入权限回调」的语句只对已存在文件生效——于是新文件恒为 0600,连目录默认 ACL 的掩码也被钉住,看起来就像 umask 无效。(#9292)

  1. 确认判据:在 POSIX 上新建一个文件,stat -c '%a' <file> 返回 600;对同一目录设置 umask 后重试,结果不变(#9292)。
  2. 对照:对已存在文件执行 write,权限会按你传入的模式生效——这个差异就是本条的指纹(#9292)。
  3. 规避:新建后立即 chmod 到期望权限(例如 644)(#9292)。
  4. 上游方向:新文件分支按 0666 & ~umask 计算,或新增「新文件权限」配置项;讨论中也说明这类改动应留在文件系统层,不要动共享的原子写模块(其它调用方有意使用 0600)(#9292)。

DeepSeek Harness SSHFS / WinFsp 挂载盘上写与编辑全失败

一句话结论:原子写在写入前无条件执行一次 mkdir -p;而 SFTP 协议 v3 没有「目录已存在」这个错误码,服务端把它归到通用失败,挂载层再映射成 EPERM——于是已存在的目录也报权限错误,写路径整体不可用。 报错是 EPERM: operation not permitted, mkdir '\\sshfs\<host>\',而 read 完全正常(#9376)。

  1. 确认判据:只有写与编辑失败、读取正常;把同一目录换到本地盘立刻正常(#9376)。
  2. 规避:把工作区改到本地盘,或在挂载端调整参数(去掉强制安全描述符转换、开启卷前缀之类的选项)以避开该错误映射(#9376)。
  3. 第二层坑:同一挂载上对暂存文件做 chmod 还会返回 EINVAL,所以即使绕过 mkdir 也要一并容忍这个错误(#9376)。
  4. 修法方向:ensureDirectory 容忍 EPERM/EACCES 并再 stat 确认目录确实存在;讨论中给出了在真实 SSHFS 挂载上跑通全链的分支(#9376)。

DeepSeek Harness 编辑:两处「看起来是保护,实际会误伤」的行为

DeepSeek Harness 的 edit 工具在这里有两处「看似保护、实际误伤」的行为:读后文件被改动会拒绝编辑,以及重叠匹配被当成唯一目标而放行本应拒绝的编辑。

DeepSeek Harness file changed since it was read

一句话结论:这是 read-before-edit 守卫在工作——文件在你读完之后被改动了,工具要求你先重新读取再编辑。 报错是 cannot edit "…": file changed since it was read — re-read the file, then retry(#9068)。

  1. 确认:报错文本即判据;这是设计如此,不是缺陷(#9068)。
  2. 处置:先 read 再 edit;注意用 shell 的 cat / sed / grep 看文件不算「读过」,必须走文件工具(#9068)。
  3. 用提示词减少复发:要求模型「改文件前先 read」写进规则,比每次撞错再补读便宜(#9068)。

DeepSeek Harness 重叠匹配被当成唯一目标

一句话结论:匹配计数器的步进方式是「本次匹配起点 + 匹配长度」,于是跳过了落在前一个匹配内部的合法起点;在单次替换模式下计数不超过 1,因此不会报歧义——结果是该拒绝的编辑被放行**,文件被改了。**(#8978)

  1. 复现判据(讨论中给的例子):文件里连续三行都是 item,用 old_str = 两行 item 去替换——因为两段匹配重叠,正确行为是报歧义并保持文件不变,实际却改了文件(#8978)。
  2. 规避:编辑时给足上下文,让匹配目标在全文中唯一(#8978)。
  3. 改法方向:枚举所有可能起点(而不是跳过重叠区),并让「全量替换」仍按非重叠计数(#8978)。

DeepSeek Harness 搜索:权限墙下把已扫结果整单作废

一句话结论:搜索在退出码非 0 且非 1 时先抛错**,而「输出已经拿到结果」的返回逻辑排在抛错之后、永远执行不到——于是哪怕已经扫到几百行,也整单作废,模型很容易把「搜索失败」误读成「文件不存在」。** 症状是在 C:\Program Files 这类含权限墙的树里,glob 以 exit 2 结束且结果为空(#9364)。

  1. 确认判据:观察退出码为 2,同时标准输出里其实已经有结果行(讨论中实测已有 641 行)(#9364)。
  2. 规避:把搜索范围收窄到确实可读的目录,或先自己用命令行确认目标是否存在(#9364)。
  3. 改法方向:把「退出码 2 且输出非空」判成部分成功(而不是整体失败),并把「结果是否完整」作为一等字段返回给调用方(#9364)。

DeepSeek Harness 打包形态:asar 内路径的 BigInt 崩溃

一句话结论:探测路径时假设 stat 的 bigint 选项会返回 BigInt 字段,而 asar 归档层会忽略该选项、返回普通数值,数值与 BigInt 混算直接抛错;放大器是「一个不可读的根会让整个文件系统技能提供者被跳过」,所以表现成技能目录整块为空**。** 报错是 TypeError: Cannot mix BigInt and other types(#9189、#9861、#8842)。

DeepSeek Harness 五步确认与处置

  1. 确认判据:只有打包(安装)形态复现,源码运行正常;日志里约每十几秒出现一次同一 TypeError(重试刷屏)(#9861)。
  2. 规避一:把技能目录指向真实磁盘路径,避开归档内部路径(#9189)。
  3. 规避二:在 profile 里覆盖技能目录配置,去掉指向归档内部的那一条(#9189)。
  4. 修法:权限掩码运算前先把值转成普通数值(讨论中社区给出的改法就是把 Number(x.mode) & 0o777 这类写法补上),并给每个根加独立 try/catch,避免一个坏根拖垮整个提供者(#9861、#8815)。
  5. 验证:重启后确认技能列表非空、日志不再刷同一错误(#9861)。

DeepSeek Harness 大文件:结果卡片 diff 把宿主冻住

一句话结论:结果卡片要算一次差异对比,而这次计算在宿主主线程上同步执行、既没有超时也没有工作量上限;差异算法在极端情况下接近二次复杂度,几千行的一次覆盖就能冻住约 8 秒——期间所有会话的流式输出、定时器、API 与连接一起停摆。(#9371) 这类「宿主整体冻住、所有会话一起停摆」的现象,也可能来自工具调用被卡住或超时,可对照 DeepSeek Harness 工具参数非法 JSON:MALFORMED_RESPONSE、bash 超时与快照失真 一并排查。

  1. 确认判据:卡顿与「单次写入行数」强相关,而不是与文件数或会话数相关;卡顿时宿主整体无响应(#9371)。
  2. 规避:大文件改写改用命令行工具生成,或把一次覆盖拆成多步小改(#9371)。
  3. 修法方向:给这次计算加上超时与长度上限(讨论中提到同项目另一处已有类似预算参数可参照),超时就退化成整文件卡片(#9371)。

DeepSeek Harness 附带更细的坑:预览窗口把 U+FEFF 吃掉且少报字节

一句话结论:解码窗口起点时把字节序标记当作文档开头处理,于是静默丢掉一个 U+FEFF,并且省略字节数的统计没有算上这一次多吞的字节——结果是内容少了但「已截断」标志仍为假。(#9506)

  1. 判据:对含 U+FEFF 的行做搜索/预览时字符消失,而读取整文件时能看到(#9506)。
  2. 处置:需要看原文时改用 read 直接读该文件;修法是在解码器上显式关闭字节序标记处理(讨论中提到同项目其它模块已有此写法可参照)(#9506)。

DSH插件 排查注意事项

文件工具的问题几乎全部集中在「文件系统差异」与「极端输入」两类,所以先问两个问题:目标盘是什么文件系统?这次输入有多大或多特殊? 九条要点:

  1. 新建 0600 / 已存在按模式:这个差异能一眼定到权限那条(#9292)。
  2. 「写不了但能读」是挂载盘的指纹(#9376)。
  3. mkdir -p 在非 POSIX 语义的文件系统上不可信(#9376)。
  4. 打包形态才复现的问题先怀疑归档层(#9189)。
  5. 一个坏根会拖垮整个技能提供者,看到「整块为空」要想到这一层(#8842)。
  6. 卡顿与写入行数强相关就是 diff 那条(#9371)。
  7. glob 返回空别当成「文件不存在」:先看退出码与输出(#9364)。
  8. 编辑歧义被放行是危险项:连续重复内容处编辑要格外给足上下文(#8978)。
  9. 修复状态如实:以上各条在讨论所指版本里都未修;社区给出的补丁分支(例如 BigInt 那两处写法)未合入,本文的处置均为用户侧规避与配置调整。

文件工具的问题常常和「工作区放在哪」纠缠在一起,尤其是挂载盘与打包形态这两类。如果你希望把「环境」这一层先看准,与其在各处手敲命令,不如用 DSH Plugin Hub 这类可视化插件市场:已安装列表、装卸历史与系统日志集中在一个面板里。

设置

来源:Discussion #9292、Discussion #9376、Discussion #9189、Discussion #9861、Discussion #8842、Discussion #8815、Discussion #9371、Discussion #9364、Discussion #8978、Discussion #9068、Discussion #9506。

常见问题

DeepSeek Harness 的 write 工具新建出来的文件权限总是 0600,umask 也设了但没用,怎么办?

在 DeepSeek Harness 里,新文件恒为 0600 是因为新建文件这条分支只应用了内部的保护模式,而“按传入权限改回”的语句只对已存在文件生效。结果是新文件恒为 0600,同时把目录默认 ACL 的掩码也钉住了,所以看起来“umask 无效”。可控的规避是新建后再执行一次 chmod 到期望权限;长期修法是新文件分支按 umask 计算(例如 0666 与取反的 umask 相与),或新增一个“新文件权限”配置项。

在 DeepSeek Harness 里把工作区放在 SSHFS 挂载盘上,write 与 edit 全部失败并报 EPERM: operation not permitted, mkdir,怎么解决?

在 DeepSeek Harness 里,这是因为原子写会无条件执行一次 mkdir -p,而 SFTP 这类协议没有“目录已存在”这个错误码,服务端把它归到通用失败,挂载层再映射成 EPERM。可行做法是把工作区改到本地盘,或改用容忍 EPERM 的实现(先执行再确认目录是否真的存在);read 不受影响这一点可以用来快速确认是写入路径的问题。

在 DeepSeek Harness 打包版桌面上,技能目录整块是空的、日志刷 Cannot mix BigInt and other types,是什么原因?

在 DeepSeek Harness 里,这是因为组合文件系统在探测路径时假设 stat 的 bigint 选项会返回 BigInt 字段,而 asar 归档层会忽略这个选项、返回普通数值,于是数值与 BigInt 混算直接抛错;更严重的是一个不可读的根会让整个文件系统技能提供者被跳过,所以表现成“技能目录整块为空”。规避是把技能目录指向真实磁盘路径;修法是把掩码运算前先转成普通数值,并给每个根加独立容错。

用 write 覆盖一个几千行的文件时,整个 DeepSeek Harness 会卡住好几秒,所有会话都停一下,为什么?

在 DeepSeek Harness 里,这是因为结果卡片要算一次差异对比,而这次计算是在宿主主线程上同步执行的、没有超时也没有工作量上限。差异算法在极端情况下接近二次复杂度,几千行的一次覆盖就能冻住约 8 秒。规避是大文件改写改用命令行工具生成或分批小步修改;修法是给这次计算加上超时与长度上限,超时就退化成整文件卡片。

在 DeepSeek Harness 里用 glob 在 C:\Program Files 这类目录搜索,明明有权限看到的文件却没返回、还报获取文件信息失败,怎么解释?

在 DeepSeek Harness 里,这是因为搜索在退出码非 0 且非 1 时先抛错,而“输出已经拿到了结果”的返回逻辑排在抛错之后,永远执行不到。于是即便已经扫到几百行结果,也会整单作废,模型容易把“搜索失败”误读成“文件不存在”。判据是退出码为 2 同时标准输出非空;修法是把这种情形判成部分成功,并把“是否完整”作为一等字段返回。

相关术语

writeFileAtomic(原子写)
writeFileAtomic 是 DeepSeek Harness 文件系统层用来安全落盘的写法:先写临时文件、再原子发布到目标路径,以避免半写状态。它会在写入前确保目录存在,因此在「已存在目录却返回权限错误」的文件系统上会整体失败。— https://github.com/deepseek-ai/deepseek-harness/discussions/9376
fs-local probe
fs-local probe 是 DeepSeek Harness 文件系统技能在列出根目录时做的路径探测,用 stat 加上 bigint 选项读取元数据并计算权限掩码。在忽略该选项的归档文件系统上,它会因为数值与 BigInt 混算而抛错。— https://github.com/deepseek-ai/deepseek-harness/discussions/9861
read-before-edit 守卫
read-before-edit 守卫是编辑工具的一道保护:要求本次编辑前文件内容必须已被读取过,且读后未被其它进程改动。文件在读取之后发生变化时,编辑会被拒绝并提示重新读取。— https://github.com/deepseek-ai/deepseek-harness/discussions/9068
TextRetainer
TextRetainer 是 DeepSeek Harness 里对过长文本做首尾保留并汇报省略字节数的组件。它在解码窗口起点时会把字节序标记当作文档开头处理,从而静默丢掉一个 U+FEFF 并少报省略量。— https://github.com/deepseek-ai/deepseek-harness/discussions/9506

来源