[GH-ISSUE #2020] [Bug] Empty package main prevents the legacy index fallback used by Node #672

Closed
opened 2026-10-15 18:27:14 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @xu91102 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2020

Before submitting

  • Searched open/closed issues and recent/open PRs; this is a different behavior from #1939 and the open package-pattern work #2018.
  • Uses source-owned fixtures with no credentials or private target data.

Area

Evidence, artifacts, or reconstruction — JavaScript application analysis.

Observed behavior

Node prints 42 and exits 0. REA reports fixture as unavailable with resolved_path null, even though the index.js file is inventoried.

Reproduction

In a built source checkout, materialize the fixture:

node --input-type=module <<'JS'
import { mkdirSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
const root = resolve("fixture");
const files = {
  "entry.mjs": "import value from \"fixture\"; console.log(value);",
  "node_modules/fixture/package.json": "{\"main\":\"\"}",
  "node_modules/fixture/index.js": "module.exports = 42;"
};
for (const [path, text] of Object.entries(files)) {
 const target = resolve(root,path);
 mkdirSync(dirname(target),{recursive:true});
 writeFileSync(target,text);
}
JS
node fixture/entry.mjs
node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --format json > observed.json

Inspect normalized_result.graph.edges for specifier, resolved_path, and resolution_status, or source-map-original nodes and the graph coverage. The affected source checkout was built and the public CLI was executed on these exact fixture shapes before this report.

Expected behavior

Treat the empty main string like no main entry and resolve the legacy index file, as the real Node import and require loaders do. Preserve refusal for genuinely invalid metadata.

Format/loader reference. Runtime/decoder controls were executed rather than inferred from documentation.

Impact and scope

Static dependency graphs disagree with actual Node module lookup. No live browser or native engine is required to reproduce the local directory-analysis failure.

Version and runtime

  • Source revision: 2ff850de68dc9b05c6faf2bbfd26d56bc2d5d27c (main at investigation start).
  • Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64.
  • Interface: compiled CLI.
  • Target: source-owned local directory.

Source-derived analysis

resolveDirectory selects the empty main value and reports invalid package JSON instead of using its index fallback.

Originally created by @xu91102 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2020 ### Before submitting - [x] Searched open/closed issues and recent/open PRs; this is a different behavior from #1939 and the open package-pattern work #2018. - [x] Uses source-owned fixtures with no credentials or private target data. ### Area Evidence, artifacts, or reconstruction — JavaScript application analysis. ### Observed behavior Node prints 42 and exits 0. REA reports fixture as unavailable with resolved_path null, even though the index.js file is inventoried. ### Reproduction In a built source checkout, materialize the fixture: ```sh node --input-type=module <<'JS' import { mkdirSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; const root = resolve("fixture"); const files = { "entry.mjs": "import value from \"fixture\"; console.log(value);", "node_modules/fixture/package.json": "{\"main\":\"\"}", "node_modules/fixture/index.js": "module.exports = 42;" }; for (const [path, text] of Object.entries(files)) { const target = resolve(root,path); mkdirSync(dirname(target),{recursive:true}); writeFileSync(target,text); } JS node fixture/entry.mjs node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --format json > observed.json ``` Inspect `normalized_result.graph.edges` for `specifier`, `resolved_path`, and `resolution_status`, or source-map-original nodes and the graph coverage. The affected source checkout was built and the public CLI was executed on these exact fixture shapes before this report. ### Expected behavior Treat the empty main string like no main entry and resolve the legacy index file, as the real Node import and require loaders do. Preserve refusal for genuinely invalid metadata. [Format/loader reference](https://nodejs.org/api/modules.html#folders-as-modules). Runtime/decoder controls were executed rather than inferred from documentation. ### Impact and scope Static dependency graphs disagree with actual Node module lookup. No live browser or native engine is required to reproduce the local directory-analysis failure. ### Version and runtime - Source revision: `2ff850de68dc9b05c6faf2bbfd26d56bc2d5d27c` (main at investigation start). - Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64. - Interface: compiled CLI. - Target: source-owned local directory. ### Source-derived analysis resolveDirectory selects the empty main value and reports invalid package JSON instead of using its index fallback.
bsakaguchi 2026-10-15 18:27:14 +00:00
Author
Owner

@CassieFox23 commented on GitHub (Oct 12, 2026):

TL;DR: I could not reproduce this on main. I did see the bug on the commit just before the fix. The fix is c0904b4c1.

Thanks, xu91102, for the clear report. I ran your fixture on Linux.

Run Result
Node 22.23.1 prints 42, exit 0
Node 24.18.0 prints 42, exit 0
Node 26.11.1 prints 42, exit 0
REA d9d2a1738, before the fix unavailable, path null
REA d96550f2f, main resolved to index.js

Each Node version finds the index.js file inside the fixture package.

Not run

  • A package main that is invalid (your "keep the refusal" case).
  • The MCP interface. I used the compiled CLI only.
  • macOS and Windows.
Commands

Fixture files, as in your issue, under /tmp/nodebatch/fx/2020:

entry.mjs                            import value from "fixture"; console.log(value);
node_modules/fixture/package.json    {"main":""}
node_modules/fixture/index.js        module.exports = 42;
# build each tree (Node 24.18.0 first on PATH, npm 11.16.0)
npm ci && npm run build && npm run test:prepare

# Node, exit codes read from each run
/usr/bin/node /tmp/nodebatch/fx/2020/entry.mjs                                  # 22.23.1 (also run with 24.18.0 and 26.11.1)

# REA, once per tree
node /tmp/nodebatch/main/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2020 --format json > main-2020.json
node /tmp/nodebatch/base/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2020 --format json > base-2020.json

REA fields, as seen in the graph edges:

d9d2a1738 (before the fix):  resolution_status "unavailable", resolved_path null
d96550f2f (main):            resolution_status "resolved", resolved_path "node_modules/fixture/index.js"

Both trees print 6.4.0 for --version, so the version string does not tell them apart. The shas do.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 22.23.1, 24.18.0, 26.11.1
  • Head / base: d96550f2f (main) / d9d2a1738 (the parent of c0904b4c1)

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6129431560 --> @CassieFox23 commented on GitHub (Oct 12, 2026): **TL;DR:** I could not reproduce this on main. I did see the bug on the commit just before the fix. The fix is c0904b4c1. Thanks, xu91102, for the clear report. I ran your fixture on Linux. | Run | Result | |---|---| | Node 22.23.1 | prints 42, exit 0 | | Node 24.18.0 | prints 42, exit 0 | | Node 26.11.1 | prints 42, exit 0 | | REA d9d2a1738, before the fix | unavailable, path null | | REA d96550f2f, main | resolved to index.js | Each Node version finds the index.js file inside the fixture package. ### Not run - A package main that is invalid (your "keep the refusal" case). - The MCP interface. I used the compiled CLI only. - macOS and Windows. <details> <summary>Commands</summary> Fixture files, as in your issue, under /tmp/nodebatch/fx/2020: ``` entry.mjs import value from "fixture"; console.log(value); node_modules/fixture/package.json {"main":""} node_modules/fixture/index.js module.exports = 42; ``` ```sh # build each tree (Node 24.18.0 first on PATH, npm 11.16.0) npm ci && npm run build && npm run test:prepare # Node, exit codes read from each run /usr/bin/node /tmp/nodebatch/fx/2020/entry.mjs # 22.23.1 (also run with 24.18.0 and 26.11.1) # REA, once per tree node /tmp/nodebatch/main/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2020 --format json > main-2020.json node /tmp/nodebatch/base/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2020 --format json > base-2020.json ``` REA fields, as seen in the graph edges: ``` d9d2a1738 (before the fix): resolution_status "unavailable", resolved_path null d96550f2f (main): resolution_status "resolved", resolved_path "node_modules/fixture/index.js" ``` Both trees print 6.4.0 for --version, so the version string does not tell them apart. The shas do. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 22.23.1, 24.18.0, 26.11.1 - Head / base: d96550f2f (main) / d9d2a1738 (the parent of c0904b4c1) </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#672
No description provided.