[GH-ISSUE #6798] [Bug] createRequire with a different filename resolves dependencies relative to the caller #4149

Closed
opened 2026-10-31 00:47:10 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6798

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

analyze-javascript-application resolves a literal dependency from a proven createRequire loader relative to the source file instead of the filename passed to createRequire. In the fixture below, Node loads nested/dep.cjs, while REA emits an imports edge with resolved_path: "dep.cjs", resolution_status: "resolved", high confidence and complete coverage.

A createRequire(import.meta.url) control correctly loads and maps the root dep.cjs. Both public CLI analyses and both separate Node runtime controls exited 0. Each case ran once before this draft. No browser or external target was used; REA analyzed the sources statically.

Reproduction

Create an absolute fixture directory with these four files:

// main.mjs
import { createRequire } from 'node:module';
const load = createRequire(new URL("./nested/anchor.cjs", import.meta.url));
console.log(load('./dep.cjs'));
// dep.cjs
module.exports="ROOT";
// nested/dep.cjs
module.exports="NESTED";

nested/anchor.cjs is empty.

node "$FIXTURE/main.mjs"
node "$REA_ROOT/scripts/rea.mjs" analyze-javascript-application "$FIXTURE" --format json

The first command prints NESTED. In the second result, select the normalized_result.graph.edges import whose properties.specifier is ./dep.cjs: it resolves to dep.cjs, the file that would print ROOT.

For the executed control, the only source change was replacing new URL("./nested/anchor.cjs", import.meta.url) with import.meta.url. Node then prints ROOT, and REA still resolves dep.cjs.

Expected behavior

The relocated loader should map ./dep.cjs to nested/dep.cjs, preserving the loader's explicit base filename. If that base cannot be carried through, the relationship should remain unresolved with a limitation instead of confidently selecting a different inventoried module. The separate Node executions establish the expected resolution for this fixture.

Impact and scope

Ordinary ESM code that creates a CommonJS loader for another file can acquire false dependency edges when the same dependency name exists beside both files. The demonstrated result is incorrect module ownership in successful analysis output. Broader third-party application frequency and downstream behavior were not measured. No practical result-preserving workaround was verified.

REA version

6.7.0; source revision bd4f5e9c197ba942ed026c9fed6ff3fae663901d, prepared build from that checkout.

Runtime and platform

Node v26.12.1; Linux x86_64.

Target and artifact context

Local directory containing an ESM entry point and two CommonJS dependencies; all files were available to the analyzer.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

createRequire argument Node stdout REA resolved path Resolution Confidence / coverage
import.meta.url ROOT dep.cjs resolved high / complete
new URL("./nested/anchor.cjs", import.meta.url) NESTED dep.cjs resolved high / complete

The domain loader analysis recognizes a different relative filename and retains it as sourceRelativePath. The static-reference projection keeps only the call's specifier; graph resolution then uses the original source path. This is source-derived explanation of the observed CLI result.

Additional context

The closed #6612 reports loader-base loss in historical reference-source import. This report concerns the separate current-artifact application graph: its static-reference projection drops the recognized base before JavaScriptArtifactGraphFindings resolves the edge. The current CLI observation above establishes that this application-analysis path remains affected. Related #4189 concerns trailing-slash CommonJS package-main lookup, and #4269 concerns escaped ESM historical paths; neither is used here.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The public CLI reports a resolved high-confidence dependency on an inventoried file different from the one selected by Node for the same source; the current-file control isolates the loader base as the trigger.
  • Workaround status: unverified
  • Workaround basis: No workaround preserving the selected source and its dependency relationships was tested; changing the loader to use the current filename changes runtime behavior in the control.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6798 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Evidence, artifacts, or reconstruction ## Observed behavior `analyze-javascript-application` resolves a literal dependency from a proven `createRequire` loader relative to the source file instead of the filename passed to `createRequire`. In the fixture below, Node loads `nested/dep.cjs`, while REA emits an `imports` edge with `resolved_path: "dep.cjs"`, `resolution_status: "resolved"`, high confidence and complete coverage. A `createRequire(import.meta.url)` control correctly loads and maps the root `dep.cjs`. Both public CLI analyses and both separate Node runtime controls exited 0. Each case ran once before this draft. No browser or external target was used; REA analyzed the sources statically. ## Reproduction Create an absolute fixture directory with these four files: ```js // main.mjs import { createRequire } from 'node:module'; const load = createRequire(new URL("./nested/anchor.cjs", import.meta.url)); console.log(load('./dep.cjs')); ``` ```js // dep.cjs module.exports="ROOT"; ``` ```js // nested/dep.cjs module.exports="NESTED"; ``` `nested/anchor.cjs` is empty. ```sh node "$FIXTURE/main.mjs" node "$REA_ROOT/scripts/rea.mjs" analyze-javascript-application "$FIXTURE" --format json ``` The first command prints `NESTED`. In the second result, select the `normalized_result.graph.edges` import whose `properties.specifier` is `./dep.cjs`: it resolves to `dep.cjs`, the file that would print `ROOT`. For the executed control, the only source change was replacing `new URL("./nested/anchor.cjs", import.meta.url)` with `import.meta.url`. Node then prints `ROOT`, and REA still resolves `dep.cjs`. ## Expected behavior The relocated loader should map `./dep.cjs` to `nested/dep.cjs`, preserving the loader's explicit base filename. If that base cannot be carried through, the relationship should remain unresolved with a limitation instead of confidently selecting a different inventoried module. The separate Node executions establish the expected resolution for this fixture. ## Impact and scope Ordinary ESM code that creates a CommonJS loader for another file can acquire false dependency edges when the same dependency name exists beside both files. The demonstrated result is incorrect module ownership in successful analysis output. Broader third-party application frequency and downstream behavior were not measured. No practical result-preserving workaround was verified. ## REA version 6.7.0; source revision `bd4f5e9c197ba942ed026c9fed6ff3fae663901d`, prepared build from that checkout. ## Runtime and platform Node v26.12.1; Linux x86_64. ## Target and artifact context Local directory containing an ESM entry point and two CommonJS dependencies; all files were available to the analyzer. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence | `createRequire` argument | Node stdout | REA resolved path | Resolution | Confidence / coverage | | --- | --- | --- | --- | --- | | `import.meta.url` | `ROOT` | `dep.cjs` | resolved | high / complete | | `new URL("./nested/anchor.cjs", import.meta.url)` | `NESTED` | `dep.cjs` | resolved | high / complete | The domain loader analysis [recognizes a different relative filename](https://github.com/morluto/rea/blob/bd4f5e9c197ba942ed026c9fed6ff3fae663901d/src/domain/javascript/javascriptSemanticRequireOrigin.ts#L299-L319) and [retains it as `sourceRelativePath`](https://github.com/morluto/rea/blob/bd4f5e9c197ba942ed026c9fed6ff3fae663901d/src/domain/javascript/javascriptSemanticRequireOrigin.ts#L610-L622). The static-reference projection [keeps only the call's specifier](https://github.com/morluto/rea/blob/bd4f5e9c197ba942ed026c9fed6ff3fae663901d/src/domain/javascript/javascriptStaticAnalysisCalls.ts#L263-L283); graph resolution then [uses the original source path](https://github.com/morluto/rea/blob/bd4f5e9c197ba942ed026c9fed6ff3fae663901d/src/application/javascript/JavaScriptArtifactGraphFindings.ts#L669-L687). This is source-derived explanation of the observed CLI result. ## Additional context The closed [#6612](https://github.com/morluto/rea/issues/6612) reports loader-base loss in historical reference-source import. This report concerns the separate current-artifact application graph: its static-reference projection drops the recognized base before `JavaScriptArtifactGraphFindings` resolves the edge. The current CLI observation above establishes that this application-analysis path remains affected. Related #4189 concerns trailing-slash CommonJS package-main lookup, and #4269 concerns escaped ESM historical paths; neither is used here. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The public CLI reports a resolved high-confidence dependency on an inventoried file different from the one selected by Node for the same source; the current-file control isolates the loader base as the trigger. - Workaround status: unverified - Workaround basis: No workaround preserving the selected source and its dependency relationships was tested; changing the loader to use the current filename changes runtime behavior in the control.
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#4149
No description provided.