Skip to content

With "type": "commonjs", #!/usr/bin/env node file does not execute but returns success and no error messages when the file is ESM #61104

Description

@0cjs

Version

v24.11.1

Platform

Linux academic 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.129-1 (2025-03-06) x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Create a package.json containing only {}. Create the following file script and chmod it executable. (Note that it's ESM, not CommonJS.)

#!/usr/bin/env node
console.log('script STARTED')
import { version } from 'node:process'
console.log(version)

In that same directory, run the script and observe that it produces the expected output and "success" exit code:

$ ./script ; echo "===== exitcode=$?"
script STARTED
v24.11.1
===== exitcode=0

Now add to your package.json the line "type": "commonjs". Run the script again, and note that it produces no output at all (neither what it is expected to print nor any errors), and yet still exits with exit code 0, indicating success:

$ ./script ; echo "===== exitcode=$?"
===== exitcode=0

If you feel like it, you can replace the ESM import with const { version } = require('node:process') and see that it does work as in the first example run above.

How often does it reproduce? Is there a required condition?

Always reproduces.

What is the expected behavior? Why is that the expected behavior?

I expect the "type": "commonjs" case to do two things, in order of importance:

  1. Exit with a non-zero exit code (indicating "failure") because it didn't run. This would help avoid the especially insidious situation where it's a script running in a build system that's expected to do something important but produce no output. (Ask me how I know this is "insidious." :-))

  2. Print some sort of error to stderr indicating that the script can't be run, ideally including some information about the configuration that's preventing this. (In this case, I guess, it's that the auto-detection of ESM vs. CommonJS based on file contents is disabled due to the "type": "commonjs" in package.json?)

What do you see instead?

See output in reproduction above.

Additional information

node --print-all-exceptions ./script >exceptions.txt 2>&1 may have some useful information in its 1240 lines. I've attached the output from my machine as exceptions.txt.

Also, possibly #49444 "Feature: ESM in executable files" may have some relation to this, though I've not read through it carefully (it's a long read).

Activity

  1. changed the title [-]`#!/usr/bin/env node` file does not execute but returns success and no error messages when the file is ESM[/-] [+]With `"type": "commonjs"`, `#!/usr/bin/env node` file does not execute but returns success and no error messages when the file is ESM[/+] on Dec 18, 2025
  2. aduh95 commented on Dec 18, 2025

    @aduh95
    Contributor

    I'm able to reproduce on main and up to 20.19.6 with the following:

    mkdir repro && {(
        cd repro
        echo '{ "type": "commonjs" }' > package.json
        printf '#!/usr/bin/env node\nprocess.exitCode=42;export {}\n' > script
        chmod +x script
        NODE_DEBUG=* ./script
        echo "Exit code was $?"
      )
      rm -rf repro
    }

    The output is

    MODULE 72559: looking for "…/repro/script" in […]
    MODULE 72559: load "…/repro/script" for module "."
    MODULE_TIMER 72559 [] […/repro/script]: 6.926ms
    ESM 72559: Translating CJSModule file://…/repro/script
    ESM 72559: Preparsing exports of …/repro/script
    ESM 72559: Storing file://…/repro/script (implicit type) in ModuleLoadMap
    ESM 72559: ModuleJob.run() ModuleWrap {
      url: 'file://…/repro/script',
      [Symbol(imported_cjs_symbol)]: {
        id: '.',
        path: '…/repro',
        exports: {},
        filename: '…/repro/script',
        loaded: true,
        children: [],
        paths: [
          '…/repro/node_modules',
          '…/node_modules',
           …
        ],
        [Symbol(kIsMainSymbol)]: true,
        [Symbol(kIsCachedByESMLoader)]: false,
        [Symbol(kURL)]: undefined,
        [Symbol(kFormat)]: undefined
      }
    }
    ESM 72559: async addJobsToDependencyGraph() file://…/repro/script ModuleJob {
      importAttributes: [Object: null prototype] {},
      isMain: true,
      inspectBrk: false,
      url: 'file://…/repro/script',
      module: ModuleWrap {
        url: 'file://…/repro/script',
        [Symbol(imported_cjs_symbol)]: {
          id: '.',
          path: '…/repro',
          exports: {},
          filename: '…/repro/script',
          loaded: true,
          children: [],
          paths: [Array],
          [Symbol(kIsMainSymbol)]: true,
          [Symbol(kIsCachedByESMLoader)]: false,
          [Symbol(kURL)]: undefined,
          [Symbol(kFormat)]: undefined
        }
      },
      modulePromise: Promise {
        ModuleWrap {
          url: 'file://…/repro/script',
          [Symbol(imported_cjs_symbol)]: [Object]
        }
      },
      linked: Promise { <pending> },
      instantiated: undefined
    }
    ESM 72559: Loading CJSModule file://…/repro/script
    Exit code was 0
    
  3. aduh95 commented on Dec 18, 2025

    @aduh95
    Contributor

    /cc @nodejs/loaders

  4. added 2 commits that reference this issue on Mar 9, 2026
    9842d3e
  5. added a commit that references this issue on Mar 10, 2026
    ea87eea
  6. kjay46857-cmyk commented on Mar 19, 2026

    @kjay46857-cmyk

    6f4a4f6- [ ] ef4c3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues and PRs for confirmed bugs.loadersIssues and PRs related to ES module loaders.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions