Skip to content

netlify dev with --cwd from outside the project: every function 500s with "module is not defined in ES module scope" (detectZisiBuilder passes a string to readPackageUp) #8423

Description

@bsplatt92

Describe the bug

detectZisiBuilder determines whether the project's package.json has "type": "module" like this:

// @ts-expect-error(serhalp) -- We seem to be incorrectly using this function, but it seems to work... Investigate.
const packageJson = await readPackageUp(func.mainFile)
const hasTypeModule = packageJson?.packageJson.type === 'module'

// @ts-expect-error(serhalp) -- We seem to be incorrectly using this function, but it seems to work... Investigate.
const packageJson = await readPackageUp(func.mainFile)
const hasTypeModule = packageJson?.packageJson.type === 'module'

read-package-up expects an options object ({ cwd }), not a file path string. The string is silently ignored (find-up reads options.cwd, which is undefined), so the lookup always starts from process.cwd() instead of the function's directory. The @ts-expect-error TODO on that line is exactly this bug — it only "seems to work" because process.cwd() is usually inside the project.

It stops working when netlify dev is run with --cwd <project> from a directory outside the project: the CLI honors --cwd for config resolution but never calls process.chdir(), so readPackageUp searches upward from the invocation directory. If no package.json exists there or in its ancestors, hasTypeModule is false, and buildFunction skips writing the {"type":"commonjs"} marker into each function's .netlify/functions-serve/<name>/ directory:

// some projects include a package.json with "type=module", forcing Node to interpret every descending file
// as ESM. ZISI outputs CJS, so we emit an overriding directive into the output directory.
if (hasTypeModule) {
await writeFile(
path.join(functionPath, 'package.json'),
JSON.stringify({
type: 'commonjs',
}),
)
}

In a project whose root package.json has "type": "module", Node then parses every zisi/esbuild CJS function bundle as ESM, and every function invocation 500s with:

ReferenceError: module is not defined in ES module scope

Running the identical command from inside the project works (the buggy fallback happens to resolve the right package.json), which is presumably why this is rarely reported. Editors/wrappers that spawn netlify dev --cwd <project> with a different working directory hit it every time.

A secondary effect of the same line: mustUseEsbuild = hasTypeModule || mustTranspile is also computed from the wrong package.json, so a "type": "module" project with plain .js functions and no explicit node_bundler wouldn't get esbuild auto-selected either.

Suggested fix

const packageJson = await readPackageUp({ cwd: path.dirname(func.mainFile) })

This is exactly what @netlify/functions-dev already does in its equivalent code path (its dist/main.js: readPackageUp({ cwd: path.dirname(func.mainFile) })), and it lets you drop the @ts-expect-error. Happy to open a PR.

Steps to reproduce

  1. Create a project with:
    • root package.json containing "type": "module"
    • netlify.toml with [functions] node_bundler = "esbuild" and a v1 TypeScript function (e.g. netlify/functions/hello.ts)
  2. From a directory outside the project that has no package.json in itself or any ancestor (e.g. C:\ or a fresh temp dir), run:
    netlify dev --cwd /path/to/project
    
  3. curl http://localhost:8888/.netlify/functions/hello500, terminal shows ReferenceError: module is not defined in ES module scope, and .netlify/functions-serve/hello/ contains no package.json marker.
  4. Run the same netlify dev from inside the project directory → the function works and the {"type":"commonjs"} marker is written.

Verified on netlify-cli 26.0.1; the code is unchanged in v27.1.1 and current main (85c0113). Patching the installed dist/lib/functions/runtimes/js/builders/zisi.js with the one-line fix above resolves it.

Configuration

[build]
  publish = "dist"

[functions]
  node_bundler = "esbuild"

Environment

  System:
    OS: Windows 11 10.0.26200
    CPU: (8) x64 Intel(R) Core(TM) Ultra 7 258V
    Memory: 8.57 GB / 31.49 GB
  Binaries:
    Node: 24.15.0 - C:\Program Files\nodejs\node.EXE
    npm: 11.12.1 - C:\Program Files\nodejs\npm.CMD
  npmGlobalPackages:
    netlify-cli: 26.0.1

(Reproduced on 26.0.1; bug confirmed present in 27.1.1 and main by source inspection. Not OS-specific — the lookup falls back to process.cwd() on any platform.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions