Skip to content

[BUG] Windows: ERR_UNSUPPORTED_ESM_URL_SCHEME when previewing due to raw Windows paths in import() #826

@cording12

Description

@cording12

Describe the bug

Bug Description

Running opennextjs-cloudflare preview on Windows can fail with the following error:

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:'

This occurs because the retrieveCompiledConfig() function in cli/commands/utils.ts can dynamically import a local file using a raw absolute Windows path (C:\...) rather than a proper file:// URI on the line const config = await import(configPath).then((mod) => mod.default);.

This is potentially an issue only arising in monorepos, as I have not seen it happen elsewhere. The monorepo structure hoists @opennext/cloudflare to the node_modules in the project root.

This bug is also intermittent. The first time running the preview command can run successfully.

Steps to reproduce

  1. Create a turbo repo: npx create-turbo@latest
  2. CD into apps and run npm create cloudflare@latest -- my-next-app --framework=next --platform=workers
  3. Run opennextjs-cloudflare preview
  4. Observe the error

Expected behavior

System is able to build and run correctly

@opennextjs/cloudflare version

1.6.1

Wrangler version

4.25.1

next info output

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro     
  Available memory (MB): 65365
  Available CPU cores: 16     
Binaries:
  Node: 22.17.0
  npm: 11.4.2
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.3.0
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: 5.8.3
Next.js Config:
  output: N/A

Additional context

This can be temporarily patched for Windows users if you are running into this bug. A quick manual patch:

  1. Locate the utils.ts file located in root\node_modules\@opennextjs\cloudflare\dist\cli\commands
  2. Add import { pathToFileURL } from "url"; to the top of the file
  3. Replace const config = await import(configPath).then((mod) => mod.default); with const config = await import(pathToFileURL(configPath).href).then((mod) => mod.default);

If this patch works successfully, you can automate the patching using patch-package so that you don't have to re-do this every time you re-install dependencies (or upgrade versions).

  1. In your monorepo root, run npm i patch-package --save-dev
  2. In your monorepo root, create the file : patches/@opennextjs+cloudflare+1.6.1.patch. The 1.6.1 denotes the version of the package where you must adjust accordingly, or leave as it is if you are using 1.6.1. Patches is a new folder you must create if it does not already exist.
  3. Inside @opennextjs+cloudflare+1.6.1.patch file, insert the following:
diff --git a/node_modules/@opennextjs/cloudflare/dist/cli/commands/utils.js b/node_modules/@opennextjs/cloudflare/dist/cli/commands/utils.js
index 562ba80..d232437 100644
--- a/node_modules/@opennextjs/cloudflare/dist/cli/commands/utils.js
+++ b/node_modules/@opennextjs/cloudflare/dist/cli/commands/utils.js
@@ -7,6 +7,7 @@ import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.j
 import logger from "@opennextjs/aws/logger.js";
 import { unstable_readConfig } from "wrangler";
 import { createOpenNextConfigIfNotExistent, ensureCloudflareConfig } from "../build/utils/index.js";
+import { pathToFileURL } from "url";
 export const nextAppDir = process.cwd();
 /**
  * Print headers and warnings for the CLI.
@@ -39,7 +40,8 @@ export async function retrieveCompiledConfig() {
         logger.error("Could not find compiled Open Next config, did you run the build command?");
         process.exit(1);
     }
-    const config = await import(configPath).then((mod) => mod.default);
+    // const config = await import(configPath).then((mod) => mod.default);
+    const config = await import(pathToFileURL(configPath).href).then((mod) => mod.default);
     ensureCloudflareConfig(config);
     return { config };
 }
  1. Add "postinstall": "patch-package" to your root package.json scripts. This will automatically apply after running installs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions