openclaw - ✅(Solved) Fix [Bug] `pnpm build` fails on Windows with `EPERM` while creating symlinks in `dist-runtime` [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#55454Fetched 2026-04-08 01:39:22
View on GitHub
Comments
2
Participants
2
Timeline
11
Reactions
0
Timeline (top)
cross-referenced ×5commented ×2labeled ×2referenced ×2

On Windows, pnpm build fails with EPERM: operation not permitted, symlink during runtime post-build staging into dist-runtime.

Error Message

Observed output:

[email protected] build C:\Users\pc\Desktop\openclaw pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && node scripts/build-stamp.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts

[email protected] canvas:a2ui:bundle C:\Users\pc\Desktop\openclaw bash scripts/bundle-a2ui.sh

<DIR>/a2ui.bundle.js chunk │ size: 457.10 kB

✔ rolldown v1.0.0-rc.9 Finished in 51.25 ms node:fs:1868 binding.symlink( ^

Error: EPERM: operation not permitted, symlink '..........\dist\extensions\acpx\skills\acp-router\SKILL.md' -> 'C:\Users\pc\Desktop\openclaw\dist-runtime\extensions\acpx\skills\acp-router\SKILL.md' at Object.symlinkSync (node:fs:1868:11) at ensureSymlink (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:17:8) at symlinkPath (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:38:3) at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:106:5) at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7) at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7) at stageBundledPluginRuntime (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:142:5) at runRuntimePostBuild (file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:13:3) at file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:17:3 at ModuleJob.run (node:internal/modules/esm/module_job:430:25) { errno: -4048, code: 'EPERM', syscall: 'symlink', path: '..\..\..\..\..\dist\extensions\acpx\skills\acp-router\SKILL.md', dest: 'C:\Users\pc\Desktop\openclaw\dist-runtime\extensions\acpx\skills\acp-router\SKILL.md' }

Node.js v24.14.1  ELIFECYCLE  Command failed with exit code 1.

Root Cause

Affected: Windows contributors/builds without symlink privileges or Developer Mode enabled Severity: High (blocks pnpm build) Frequency: 100% on the affected setup Consequence: Windows users cannot complete a full source build because runtime post-build staging fails

Fix Action

Fixed

PR fix notes

PR #55457: fix: fall back to copy when runtime file symlinks are denied

Description (problem / solution / changelog)

Summary

Fall back to copying runtime overlay files when file symlink creation is denied during bundled plugin runtime staging. This keeps the symlink-first behavior for normal environments but unblocks Windows builds where creating file symlinks in dist-runtime fails with EPERM/EACCES.

Changes

  • catch file-symlink permission failures in symlinkPath()
  • copy the source file into dist-runtime when symlink creation is denied
  • add a focused regression test covering the fallback path

Testing

  • pnpm exec vitest run --config vitest.unit.config.ts src/plugins/stage-bundled-plugin-runtime.test.ts
  • repository commit hook checks passed during commit (format:check, lint suite, config/schema checks, plugin boundary checks)

Fixes openclaw/openclaw#55454

Changed files

  • scripts/stage-bundled-plugin-runtime.mjs (modified, +12/-1)
  • src/plugins/stage-bundled-plugin-runtime.test.ts (modified, +35/-0)

PR #55464: fix: fallback to file copy when symlink creation fails on Windows

Description (problem / solution / changelog)

Summary

  • Problem: pnpm build fails on Windows when the runtime staging step tries to create a file symlink and Node returns EPERM or EACCES.
  • Why it matters: this blocks local builds on Windows environments where file symlink creation is restricted, such as when Developer Mode is disabled or the process is not elevated.
  • What changed: added a Windows-specific fallback to copy the file when file symlink creation is denied, and updated the related test coverage.
  • What did NOT change (scope boundary): directory symlink behavior, non-Windows behavior, and the broader build pipeline were not changed.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #55454
  • Related #
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

  • Root cause: the Windows build path attempts to create a file symlink during runtime staging, but file symlink creation may be denied on Windows without Developer Mode or elevated permissions.
  • Missing detection / guardrail: there was no fallback for file symlink creation failure on Windows for file targets.
  • Prior context (git blame, prior PR, issue, or refactor if known): Unknown.
  • Why this regressed now: this is environment-dependent and reproduces on Windows setups where file symlink creation is restricted.
  • If unknown, what was ruled out: general build flow issues were ruled out, since the build succeeds after handling the denied symlink path.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/plugins/stage-bundled-plugin-runtime.test.ts
  • Scenario the test should lock in: when file symlink creation fails on Windows with EPERM or EACCES, the staging path should fall back to copying the file.
  • Why this is the smallest reliable guardrail: it validates the exact failure-handling behavior without requiring a full Windows-specific end-to-end environment.
  • Existing test that already covers this (if any): none specific to this fallback behavior.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Windows users can now complete pnpm build successfully in environments where file symlink creation is denied, because the build falls back to copying the file.

Diagram (if applicable)

Before:
[pnpm build] -> [file symlink attempt on Windows] -> [EPERM/EACCES] -> [build fails]

After:
[pnpm build] -> [file symlink attempt on Windows] -> [EPERM/EACCES] -> [copy file fallback] -> [build succeeds]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Windows
  • Runtime/container: local Node.js environment
  • Model/provider: N/A
  • Integration/channel (if any): N/A
  • Relevant config (redacted): local checkout, build run via pnpm build

Steps

  1. Clone the repository on Windows.
  2. Run pnpm build.
  3. Observe failure during runtime staging when creating a file symlink.

Expected

  • pnpm build should complete successfully.

Actual

  • Build failed with EPERM: operation not permitted during fs.symlinkSync(...).

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: ran pnpm build on Windows before and after the change; confirmed the build passed after the fallback was added.
  • Edge cases checked: Windows-denied symlink path covered by updated test.
  • What you did not verify: non-Windows behavior beyond keeping the existing path unchanged.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: copying a file instead of symlinking may diverge slightly from the original behavior in restricted Windows environments.

    • Mitigation: fallback is only used when symlink creation fails with Windows permission-related errors; normal behavior is preserved otherwise.

Changed files

  • scripts/stage-bundled-plugin-runtime.mjs (modified, +28/-4)
  • src/plugins/stage-bundled-plugin-runtime.test.ts (modified, +6/-2)

Code Example

Observed output:

> openclaw@2026.3.24 build C:\Users\pc\Desktop\openclaw
> pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && node scripts/build-stamp.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts  


> openclaw@2026.3.24 canvas:a2ui:bundle C:\Users\pc\Desktop\openclaw
> bash scripts/bundle-a2ui.sh

<DIR>/a2ui.bundle.js  chunk │ size: 457.10 kB

✔ rolldown v1.0.0-rc.9 Finished in 51.25 ms
node:fs:1868
  binding.symlink(
          ^

Error: EPERM: operation not permitted, symlink '..\..\..\..\..\dist\extensions\acpx\skills\acp-router\SKILL.md' -> 'C:\Users\pc\Desktop\openclaw\dist-runtime\extensions\acpx\skills\acp-router\SKILL.md'
    at Object.symlinkSync (node:fs:1868:11)
    at ensureSymlink (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:17:8)
    at symlinkPath (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:38:3)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:106:5)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7)
    at stageBundledPluginRuntime (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:142:5)
    at runRuntimePostBuild (file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:13:3)
    at file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:17:3
    at ModuleJob.run (node:internal/modules/esm/module_job:430:25) {
  errno: -4048,
  code: 'EPERM',
  syscall: 'symlink',
  path: '..\\..\\..\\..\\..\\dist\\extensions\\acpx\\skills\\acp-router\\SKILL.md',
  dest: 'C:\\Users\\pc\\Desktop\\openclaw\\dist-runtime\\extensions\\acpx\\skills\\acp-router\\SKILL.md'
}

Node.js v24.14.1
ELIFECYCLECommand failed with exit code 1.
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

On Windows, pnpm build fails with EPERM: operation not permitted, symlink during runtime post-build staging into dist-runtime.

Steps to reproduce

  1. Use a Windows machine without Developer Mode/symlink privileges enabled.
  2. Clone openclaw/openclaw.
  3. Run pnpm install.
  4. Run pnpm build.
  5. Observe the build fail during runtime post-build when creating symlinks under dist-runtime.

Expected behavior

pnpm build should complete successfully on Windows and stage bundled plugin runtime artifacts into dist-runtime without failing on symlink creation.

Actual behavior

pnpm build fails during runtime post-build with EPERM: operation not permitted, symlink while staging files into dist-runtime.

OpenClaw version

2026.3.24

Operating system

Windows 11

Install method

from source (git clone + pnpm install)

Model

NOT_APPLICABLE

Provider / routing chain

NOT_APPLICABLE

Additional provider/model setup details

This issue occurs during local build/runtime staging and does not depend on model/provider configuration.

Logs, screenshots, and evidence

Observed output:

> [email protected] build C:\Users\pc\Desktop\openclaw
> pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && node scripts/build-stamp.mjs && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/copy-export-html-templates.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts && node --import tsx scripts/write-cli-compat.ts  


> [email protected] canvas:a2ui:bundle C:\Users\pc\Desktop\openclaw
> bash scripts/bundle-a2ui.sh

<DIR>/a2ui.bundle.js  chunk │ size: 457.10 kB

✔ rolldown v1.0.0-rc.9 Finished in 51.25 ms
node:fs:1868
  binding.symlink(
          ^

Error: EPERM: operation not permitted, symlink '..\..\..\..\..\dist\extensions\acpx\skills\acp-router\SKILL.md' -> 'C:\Users\pc\Desktop\openclaw\dist-runtime\extensions\acpx\skills\acp-router\SKILL.md'
    at Object.symlinkSync (node:fs:1868:11)
    at ensureSymlink (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:17:8)
    at symlinkPath (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:38:3)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:106:5)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7)
    at stagePluginRuntimeOverlay (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:83:7)
    at stageBundledPluginRuntime (file:///C:/Users/pc/Desktop/openclaw/scripts/stage-bundled-plugin-runtime.mjs:142:5)
    at runRuntimePostBuild (file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:13:3)
    at file:///C:/Users/pc/Desktop/openclaw/scripts/runtime-postbuild.mjs:17:3
    at ModuleJob.run (node:internal/modules/esm/module_job:430:25) {
  errno: -4048,
  code: 'EPERM',
  syscall: 'symlink',
  path: '..\\..\\..\\..\\..\\dist\\extensions\\acpx\\skills\\acp-router\\SKILL.md',
  dest: 'C:\\Users\\pc\\Desktop\\openclaw\\dist-runtime\\extensions\\acpx\\skills\\acp-router\\SKILL.md'
}

Node.js v24.14.1
 ELIFECYCLE  Command failed with exit code 1.

Impact and severity

Affected: Windows contributors/builds without symlink privileges or Developer Mode enabled Severity: High (blocks pnpm build) Frequency: 100% on the affected setup Consequence: Windows users cannot complete a full source build because runtime post-build staging fails

Additional information

This appears to be a Windows-specific issue in runtime post-build staging, where file symlink creation in dist-runtime fails with EPERM.

A likely fix is to keep symlink-first behavior but fall back to copying the file on Windows when symlink fails with EPERM or EACCES.

Likely code area:

  • scripts/stage-bundled-plugin-runtime.mjs

I can open a focused PR if this direction looks good.

extent analysis

Fix Plan

To resolve the issue, we need to modify the stage-bundled-plugin-runtime.mjs script to fall back to copying files when symlink creation fails with EPERM or EACCES on Windows.

Here are the steps:

  • Modify the ensureSymlink function in scripts/stage-bundled-plugin-runtime.mjs to catch EPERM and EACCES errors.
  • If an error occurs, use fs.copyFileSync to copy the file instead of creating a symlink.

Example code:

import * as fs from 'node:fs';
import * as path from 'node:path';

// ...

function ensureSymlink(src, dest) {
  try {
    fs.symlinkSync(src, dest);
  } catch (error) {
    if (error.code === 'EPERM' || error.code === 'EACCES') {
      // Fall back to copying the file
      fs.copyFileSync(src, dest);
    } else {
      throw error;
    }
  }
}

// ...

Verification

To verify the fix, run pnpm build on a Windows machine without Developer Mode/symlink privileges enabled. The build should complete successfully, and the files should be staged in dist-runtime without any errors.

Extra Tips

  • Make sure to test the fix on different Windows configurations to ensure it works as expected.
  • Consider adding a log message or a warning when falling back to copying files, to inform the user that symlink creation failed.
  • If you're using a version control system, create a focused PR with the changes and test them thoroughly before merging.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

pnpm build should complete successfully on Windows and stage bundled plugin runtime artifacts into dist-runtime without failing on symlink creation.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING