openclaw - 💡(How to fix) Fix [Bug]: Node 24 + Windows: dynamic `import()` of absolute paths fails with `ERR_UNSUPPORTED_ESM_URL_SCHEME [2 comments, 3 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#72017Fetched 2026-04-27 05:36:01
View on GitHub
Comments
2
Participants
3
Timeline
10
Reactions
0
Author
Timeline (top)
labeled ×4cross-referenced ×3commented ×2closed ×1

On Windows under Node.js v24, multiple OpenClaw subsystems fail to load with:

Only URLs with a scheme in: file, data, and node are supported by the default ESM loader.
On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Root cause appears to be await import('C:/...') somewhere in the bundle without pathToFileURL(...).href. Node 22 was lenient about this; Node 24 enforces the spec, so any drive-letter path passed to import() is interpreted as a URL with scheme c: and rejected.

This affects at least: gateway/channels/discord, plugins/browser-control, plugins/voice-call, and memory (qmd backend). The gateway itself comes up ready but Discord channels exit immediately and several plugins fail to start.

Error Message

[ERROR] {"subsystem":"plugins"} plugin service failed (browser-control, plugin=browser, Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: ... Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: ... | memory | 1 (warn — falls back to builtin) | The Discord [default] and [aemeath] channels both channel exited on this error and auto-restart in a loop. The browser-control and voice-call plugin services fail to start at all. Likely candidate areas based on observed error sites:

  • One stability bundle from ~/.openclaw/logs/stability/, e.g. openclaw-stability-2026-04-26T06-00-49-534Z-20316-unhandled_rejection.json (this one is for the bonjour rejection, not the ESM error — include if reporting that as well)

Root Cause

Root cause appears to be await import('C:/...') somewhere in the bundle without pathToFileURL(...).href. Node 22 was lenient about this; Node 24 enforces the spec, so any drive-letter path passed to import() is interpreted as a URL with scheme c: and rejected.

Fix Action

Fix / Workaround

Workaround for end users in the meantime

Downgrade to Node 22 LTS (v22.x). Node 22 accepts the absolute paths Node 24 rejects, and matches the older behavior the bundle was written against.

Code Example

Only URLs with a scheme in: file, data, and node are supported by the default ESM loader.
On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

---

## Representative stack


plugin service failed (browser-control, plugin=browser,
  root=C:\Users\<user>\AppData\Roaming\npm\node_modules\openclaw\dist\extensions\browser):
  Only URLs with a scheme in: file, data, and node are supported by the default ESM loader.
  On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: ...
    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:195:11)
    at defaultLoadSync (node:internal/modules/esm/load:142:3)
    at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:796:12)
    at #loadSync (node:internal/modules/esm/loader:816:49)
    at ModuleLoader.load (node:internal/modules/esm/loader:781:26)
    at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:526:31)
    at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:577:36)
    at afterResolve (node:internal/modules/esm/loader:625:52)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:631:12)
    at onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:650:32)

13:41:58 [discord] [aemeath] channel exited: Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

---

import { pathToFileURL } from 'node:url';
// before:
await import(absPath);
// after:
await import(pathToFileURL(absPath).href);
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

On Windows under Node.js v24, multiple OpenClaw subsystems fail to load with:

Only URLs with a scheme in: file, data, and node are supported by the default ESM loader.
On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Root cause appears to be await import('C:/...') somewhere in the bundle without pathToFileURL(...).href. Node 22 was lenient about this; Node 24 enforces the spec, so any drive-letter path passed to import() is interpreted as a URL with scheme c: and rejected.

This affects at least: gateway/channels/discord, plugins/browser-control, plugins/voice-call, and memory (qmd backend). The gateway itself comes up ready but Discord channels exit immediately and several plugins fail to start.

Steps to reproduce

  1. Install Node.js v24.x on Windows
  2. npm i -g [email protected]
  3. Configure at least one Discord account in ~/.openclaw/openclaw.json
  4. Start the gateway (openclaw gateway or the Scheduled Task)
  5. Observe in the log: gateway reaches ready, but Discord channels emit channel exited: Only URLs with a scheme in: file, data, and node ... Received protocol 'c:' within a few seconds

Expected behavior

Prior observed behavior on the same machine and same Node version. On 2026-04-25, with Node v24.14.0 and OpenClaw 2026.4.24, the gateway logs at C:\tmp\openclaw\openclaw-2026-04-25.log show repeated successful boots reaching:

{"subsystem":"gateway"} ready (8 plugins: acpx, browser, device-pair, discord, memory-core, phone-control, talk-voice, voice-call; 62.1s) with 0 occurrences of Received protocol 'c:' across the entire day's log. Discord channels, the browser-control plugin service, and the voice-call plugin service started without ESM-loader errors.

Actual behavior

On 2026-04-26, with the same Node v24.14.0 and OpenClaw 2026.4.24, the gateway still reaches ready (8 plugins: ...) (C:\tmp\openclaw\openclaw-2026-04-26.log at 13:23:21), but the same log contains 54 occurrences of ERR_UNSUPPORTED_ESM_URL_SCHEME distributed as:

Subsystem Count gateway/channels/discord 47 plugins (browser-control, voice-call) 6 memory (qmd backend) 1

[ERROR] {"subsystem":"plugins"} plugin service failed (browser-control, plugin=browser, root=C:\Users<user>\AppData\Roaming\npm\node_modules\openclaw\dist\extensions\browser): Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: ... at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:195:11) at defaultLoadSync (node:internal/modules/esm/load:142:3) at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:796:12) at ModuleLoader.load (node:internal/modules/esm/loader:781:26) ...

User-visible result: Discord channels [default] and [aemeath] repeatedly emit channel exited: ... Received protocol 'c:' and auto-restart in a loop; browser-control and voice-call plugin services fail to start.

OpenClaw version

OpenClaw | `2026.4.24 (cbcfdf6)

Operating system

Windows 11 Pro 10.0.26200, x64

Install method

npm global

Model

Codex 5.4

Provider / routing chain

Codex 5.4

Additional provider/model setup details

Codex 5.4

Logs, screenshots, and evidence

## Representative stack


plugin service failed (browser-control, plugin=browser,
  root=C:\Users\<user>\AppData\Roaming\npm\node_modules\openclaw\dist\extensions\browser):
  Only URLs with a scheme in: file, data, and node are supported by the default ESM loader.
  On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: ...
    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:195:11)
    at defaultLoadSync (node:internal/modules/esm/load:142:3)
    at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:796:12)
    at #loadSync (node:internal/modules/esm/loader:816:49)
    at ModuleLoader.load (node:internal/modules/esm/loader:781:26)
    at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:526:31)
    at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:577:36)
    at afterResolve (node:internal/modules/esm/loader:625:52)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:631:12)
    at onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:650:32)

13:41:58 [discord] [aemeath] channel exited: Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

Impact and severity

Subsystem hit-counts in a single day's log (C:\tmp\openclaw\openclaw-2026-04-26.log):

SubsystemHits
gateway/channels/discord47
plugins (browser-control, voice-call)6
memory1 (warn — falls back to builtin)
process-level (unhandled rejection)1

The Discord [default] and [aemeath] channels both channel exited on this error and auto-restart in a loop. The browser-control and voice-call plugin services fail to start at all.

Earlier, the bonjour plugin emitted an unhandled rejection (CIAO ANNOUNCEMENT CANCELLED) that crashed the gateway entirely. Disabling the plugin via config (plugins.entries.bonjour.enabled = false) is what got the gateway stable enough to observe the rest. That bonjour crash may or may not be related to the same Node 24 change — flagging it for awareness.

Additional information

Suggested fix

Anywhere the bundle does await import(absPath) with absPath being a Windows filesystem path, route through pathToFileURL:

import { pathToFileURL } from 'node:url';
// before:
await import(absPath);
// after:
await import(pathToFileURL(absPath).href);

Likely candidate areas based on observed error sites:

  • Discord channel loader (gateway/channels/discord) — affects every configured Discord account
  • Browser plugin runtime loader (plugins/browser)
  • Voice-call plugin runtime loader (plugins/voice-call)
  • qmd manager module loader (memory)

A grep for await import( (and import( with non-string-literal arguments) over dist/ should surface them all.

Attachments to include with the upstream report

  • C:\tmp\openclaw\openclaw-2026-04-26.log (sanitize Discord tokens before sharing — they appear in config dumps if any)
  • One stability bundle from ~/.openclaw/logs/stability/, e.g. openclaw-stability-2026-04-26T06-00-49-534Z-20316-unhandled_rejection.json (this one is for the bonjour rejection, not the ESM error — include if reporting that as well)

Workaround for end users in the meantime

Downgrade to Node 22 LTS (v22.x). Node 22 accepts the absolute paths Node 24 rejects, and matches the older behavior the bundle was written against.

extent analysis

TL;DR

Update the code to use pathToFileURL when importing modules with absolute Windows file paths to fix the ESM loader error.

Guidance

  • Identify areas in the code where await import(absPath) is used with absPath being a Windows filesystem path.
  • Update these areas to use pathToFileURL from the node:url module to convert the absolute path to a valid file URL.
  • Use a grep search for await import( and import( with non-string-literal arguments over the dist/ directory to find all instances that need to be updated.
  • Verify that the fix works by checking the logs for the absence of ERR_UNSUPPORTED_ESM_URL_SCHEME errors.

Example

import { pathToFileURL } from 'node:url';
// before:
await import('C:/path/to/module');
// after:
await import(pathToFileURL('C:/path/to/module').href);

Notes

The issue is specific to Node.js v24 on Windows, where the default ESM loader no longer accepts absolute paths without a scheme. The suggested fix should be applied to all areas of the code that import modules with absolute Windows file paths.

Recommendation

Apply the workaround by updating the code to use pathToFileURL when importing modules with absolute Windows file paths, as this is a more targeted and long-term solution compared to downgrading to Node 22 LTS.

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

Prior observed behavior on the same machine and same Node version. On 2026-04-25, with Node v24.14.0 and OpenClaw 2026.4.24, the gateway logs at C:\tmp\openclaw\openclaw-2026-04-25.log show repeated successful boots reaching:

{"subsystem":"gateway"} ready (8 plugins: acpx, browser, device-pair, discord, memory-core, phone-control, talk-voice, voice-call; 62.1s) with 0 occurrences of Received protocol 'c:' across the entire day's log. Discord channels, the browser-control plugin service, and the voice-call plugin service started without ESM-loader errors.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING