## 一、问题现象
在 Windows 11 上使用 openclaw skills install wiki-system 安装 Skill 时,报错如下:
|
1 2 3 4 5 |
Downloading wiki-system@1.0.9 from ClawHub... Installing to C:\Users\用户名\.openclaw\workspace\skills\wiki-system... failed to install skill: Error: EPERM: operation not permitted, rename 'C:\Users\用户名\.openclaw\workspace\skills\.openclaw-install-stage-Nv8Mz6' -> 'C:\Users\用户名\.openclaw\workspace\skills\wiki-system' |
而且会触发 Node.js 的内部断言崩溃:
|
1 |
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c, line 76 |
环境信息:
- 系统:Windows 11
- Node.js:v25.2.1
- OpenClaw:2026.5.7
## 二、问题背景
OpenClaw 安装 Skill 的流程大致如下:
1. 从 ClawHub 下载 Skill 包到暂存目录 .openclaw-install-stage-随机字符
2. 调用 fs.rename() 把暂存目录重命名为最终的 Skill 名称(如 wiki-system)
3. 重命名成功后清理临时文件
这个 rename + cleanup 模式在 Linux/macOS 上运行良好,但在 Windows 上却踩了坑。
由于用户目录路径包含中文字符(C:\Users\用户名\...),最初的怀疑方向是中文路径导致 rename 失败。但在逐一排查后发现,问题远比想象中复杂。
## 三、排查过程
### 3.1 测试一:中文路径下 rename 到中文目录名
先在桌面创建带点前缀的临时目录,rename 到中文目录名,验证中文路径 + 中文目标的 rename 是否正常。
|
1 2 3 |
C:\Users\用户名>mkdir "C:\Users\用户名\Desktop\.test-stage" C:\Users\用户名>echo test > "C:\Users\用户名\Desktop\.test-stage\a.txt" C:\Users\用户名>rename "C:\Users\用户名\Desktop\.test-stage" "测试改名" |
结果:✅ 没有报错,正常通过。中文路径下 rename 到中文目录名没问题。
### 3.2 测试二:非中文路径下 rename 到中文目录名
为了排除中文路径本身的干扰,在 C 盘根目录下创建临时目录测试。
|
1 2 3 4 |
C:\Users\用户名>mkdir C:\temp-dottest C:\Users\用户名>mkdir C:\temp-dottest\.test-stage C:\Users\用户名>echo test > C:\temp-dottest\.test-stage\a.txt C:\Users\用户名>rename C:\temp-dottest\.test-stage 测试中文目录 |
结果:✅ 没有报错,正常通过。非中文路径下 rename 到中文目录名也没问题。
### 3.3 测试三:OpenClaw 的 skills 目录下模拟完整 rename 流程
在真实的 OpenClaw skills 目录(包含中文路径)下,用 cmd 的 rename 命令模拟操作。
|
1 2 3 |
C:\Users\用户名>mkdir "C:\Users\用户名\.openclaw\workspace\skills\.test-stage-real" C:\Users\用户名>echo test > "C:\Users\用户名\.openclaw\workspace\skills\.test-stage-real\a.txt" C:\Users\用户名>rename "C:\Users\用户名\.openclaw\workspace\skills\.test-stage-real" "wiki-system" |
结果:✅ 没有报错,正常通过。skills 目录下 rename 也正常。
### 3.4 测试四:Windows Defender 实时防护
怀疑新下载的文件被 Defender 扫描锁定导致 rename 时句柄未释放。
测试:添加 Defender 排除目录后重试
结果:❌ 依然报同样的错误。排除后问题未解决。
### 3.5 测试五:管理员权限
普通 CMD 下操作 skills 目录的部分操作可能权限不足。
|
1 2 |
C:\Users\用户名>ren "C:\Users\用户名\.openclaw\workspace\skills\wiki-system" "wiki-system-手工版" 拒绝访问。 |
普通 CMD 下确实权限不够,但切换到管理员 CMD 后手动 rename 正常。然而 OpenClaw 的 skill install 即使在管理员 CMD 下依然报错,所以权限也不是根因。
### 3.6 测试六:Node.js 原生 rename 测试
排除了系统和权限问题后,轮到 Node.js 本身。编写了一个测试脚本,在 skills 目录下完整模拟 OpenClaw 的操作:创建 staging 目录 -> 写入文件 -> renameSync -> promises.rename。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
=== OpenClaw Skill Install EPERM 测试 === User: 用户名 Homedir: C:\Users\用户名 Skills dir: C:\Users\用户名\.openclaw\workspace\skills [1/3] 创建 staging 目录... staging 内容 (3 项): scripts SKILL.md templates [2/3] 测试 fs.renameSync... ✅ renameSync 成功! 目标目录内容 (3 项): scripts SKILL.md templates [3/3] 测试 fs.promises.rename... ✅ promises.rename 成功! ✅ 二次 rename 也成功! ✅ 清理完成 |
结果:Node.js 原生的 renameSync 和 promises.rename 在中文路径下都能正常工作。**问题不在 Node.js。**
### 3.7 测试七:文件系统监控
使用 FileSystemWatcher 对 skills 目录进行实时监控,精确捕捉安装过程中的文件操作时序:
|
1 2 |
[10:12:54.049] 创建: C:\Users\用户名\.openclaw\workspace\skills\.openclaw-install-stage-Nv8Mz6 [10:12:54.066] 删除: C:\Users\用户名\.openclaw\workspace\skills\.openclaw-install-stage-Nv8Mz6 |
创建到删除只隔了 17 毫秒!而且全程没有捕捉到 "Renamed" 事件——说明 rename 失败了,然后立即执行了清理删除。这么短的时间内不可能完成联网下载、解压、写文件等一系列操作。
## 四、问题定位
经过多轮排查,排除了以下可能性:
- ❌ 中文路径问题(测试一、二、三全部通过)
- ❌ 带点前缀的目录名问题(测试通过)
- ❌ Windows Defender 实时防护(排除后依然报错)
- ❌ 管理员权限问题(管理员 CMD 下手动 rename 正常)
- ❌ Node.js 原生 rename 本身的问题(独立测试脚本全部通过)
最终定位:问题出在 OpenClaw 内部代码的异步时序上。
最可能的原因是 Skill 安装流程中,下载/解压文件流的 close 回调尚未完成,rename 操作就被提交了。由于文件句柄尚未释放,Windows 返回 EPERM。
线索指向:
- 断言崩溃位置 src\win\async.c:76 是 libuv 的 Windows 异步操作实现,UV_HANDLE_CLOSING 表示句柄正在关闭但又有新操作提交
- FileSystemWatcher 显示整个流程在 17ms 内完成,文件可能还没来得及写入完毕就调用了 rename
- 这是一个典型的竞态条件(race condition)
## 五、社区反馈
这个问题并非个例。OpenClaw 的 GitHub 上已有相关 Issue 和 PR:
- Issue #76194:同样反馈了 Windows 下 rename 的 EPERM 问题,覆盖 npm tar 解压和 pnpm store 安装两个场景
- PR #44568:已提交修复方案——fs.rename 失败时增加重试 + backoff 机制
说明 OpenClaw 团队已经意识到 Windows 平台下的 rename 兼容性问题,并且正在修复中。
## 六、临时解决方案
在官方修复发布前,有以下绕过方式:
方案一:手动搭建 Skill 目录(已验证可行)
在 skills/ 目录下手动创建 Skill 文件夹和 SKILL.md 文件,内容参考 ClawHub 上的描述编写,然后用 openclaw skills list 确认加载正常。缺少的脚本和模板文件不影响核心功能。
方案二:手动下载后解压(绕过 rename)
|
1 2 3 |
1. 获取 Skill 包的下载链接(从 ClawHub 或 npm registry) 2. 手动下载到 skills/ 下的临时目录 3. 用 copy + delete 代替 rename:robocopy 临时目录 wiki-system /E /MOVE |
方案三:等官方修复
关注 GitHub PR #44568,合并后 openclaw skills install 将增加 EPERM 重试机制。
## 七、总结
这次排查从中文路径怀疑开始,逐个排除系统和权限因素,最终通过 FileSystemWatcher 捕获到 17ms 的关键时序证据,将问题锁定在 OpenClaw 内部的异步竞态条件上。
如果你的 OpenClaw 在 Windows 上也遇到类似的 EPERM 错误,可以:
1. 去 GitHub 关注 Issue #76194 和 PR #44568
2. 临时方案:手动搭建 Skill 目录或用 robocopy 绕过 rename
3. 或者切换到 WSL2 环境使用 OpenClaw