Skip to content

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: 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:' #151

@nbkhope

Description

@nbkhope

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: 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:'

Detailed error message

> my-project@1.0.0 start
> tsx --import module-alias/register index.js


node:internal/modules/run_main:107
    triggerUncaughtException(
    ^
Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: 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:'
    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:195:11)
    at defaultLoad (node:internal/modules/esm/load:78:3)
    at nextLoad (node:internal/modules/esm/hooks:769:28)
    at load (file:///C:/Users/myself/git/my-project/node_modules/tsx/dist/esm/index.mjs?1775534279488:2:1777)
    at nextLoad (node:internal/modules/esm/hooks:769:28)
    at AsyncLoaderHooksOnLoaderHookWorker.load (node:internal/modules/esm/hooks:406:26)
    at handleMessage (node:internal/modules/esm/worker:251:24)
    at Immediate.checkForMessages (node:internal/modules/esm/worker:193:28)
    at process.processImmediate (node:internal/timers:504:21) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}

Node.js v25.9.0

Package Version

It works fine in module-alias 2.2.3

It breaks in module-alias 2.3.0 - 2.3.4

My environment

Windows 11

node -v
v25.9.0

npm -v
11.12.1

type package.json | findstr "module-alias\""
    "module-alias": "^2.3.4",

type package.json | findstr "\"tsx\""
    "tsx": "^4.21.0"

What does AI say?

path.join() on Windows returns a Windows backslash path like C:\Users\myself...\node_modules\bcrypt. When that bare Windows path is returned from the resolve hook back into Node's ESM loader, it's treated as a URL with . as the scheme — which ESM refuses to load.

The resolveAlias function needs to convert the result to a URL string before returning it. The import for pathToFileURL is already there at the top of the file but is never used by this branch.

Here's exactly what's wrong and where:

File: esm-loader.mjs:93
Problem: The resolver returns a raw Windows path (e.g. C:...\bcrypt) from all three return sites, but the ESM resolve hook must return either a bare specifier or a valid URL. Node 25 triggers the bug here because it enforces this strictly.
The pathToFileURL import on line 6 exists but is unused — it should wrap every returned path.
This is a bug in module-alias@2.3.4's ESM loader on Windows with Node 25. Node < 25 was more lenient about bare Windows paths reaching the loader; Node 25 is strict.

Not sure about AI's claim for the Node.js version since it works with the same Node.js when I downgrade to the module-alias version 2.2.3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions