[GH-ISSUE #2057] [Bug] CommonJS file URL strings are falsely resolved as local artifact dependencies #679

Closed
opened 2026-10-15 18:27:20 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction — JavaScript/TypeScript source relationships.

Observed behavior

require("file:///dep.cjs") is reported as a resolved dependency of inventoried dep.cjs. Node rejects this string with MODULE_NOT_FOUND. A second native control supplies a URI to an existing host file and is rejected too; the equivalent relative filename successfully loads 42.

Reproduction

From the repository root at the revision below, install dependencies and run npm run build:cached. This self-contained probe creates and removes its owned temporary fixture and compiler output:

python3 - <<'PY'
import json, os, shutil, subprocess, tempfile
from pathlib import Path
repo = Path.cwd()
env = dict(os.environ, REA_LOG_LEVEL="silent")
with tempfile.TemporaryDirectory(prefix="rea-repro-") as temp:
    fixture = Path(temp) / "source"
    fixture.mkdir()
    files = {'package.json': '{"type":"commonjs"}',
     'main.cjs': 'const value = require("file:///dep.cjs"); console.log(value);',
     'control.cjs': 'const value = require("./dep.cjs"); console.log(value);',
     'dep.cjs': 'module.exports = 42;'}
    for name, text in files.items():
        path = fixture / name
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(text + "\n")
    for name in ["main.cjs", "control.cjs"]:
        result = subprocess.run(["node", name], cwd=fixture, capture_output=True, text=True)
        print(name, "exit", result.returncode, "stdout", result.stdout.strip(),
              "MODULE_NOT_FOUND", "MODULE_NOT_FOUND" in result.stderr)
    target = fixture / "dep.cjs"
    result = subprocess.run(["node", "-e", "require(process.argv[1]);", target.as_uri()],
                            cwd=fixture, capture_output=True, text=True)
    print("existing URI", "target exists", target.is_file(), "exit", result.returncode,
          "MODULE_NOT_FOUND", "MODULE_NOT_FOUND" in result.stderr)
    result = subprocess.run(["node", str(repo / "scripts/rea.mjs"),
                             "analyze-javascript-application", str(fixture), "--format", "json"],
                            cwd=repo, env=env, capture_output=True, text=True, check=True)
    graph = json.loads(result.stdout)["normalized_result"]["graph"]
    links = [e["properties"] for e in graph["edges"] if e["relation"] == "imports"
             and "module_link_kind" in e["properties"]
             and e["evidence"]["location"].get("value", {}).get("source") == "main.cjs"]
    formats = [o["properties"]["module_format"] for n in graph["nodes"] for o in n["observations"]
               if o.get("properties", {}).get("semantic_role") == "source-module"
               and o["properties"].get("path") == "main.cjs"]
    print("REA coverage", graph["coverage"]["status"], "format", formats)
    print("REA semantic imports", json.dumps(links))
PY

Expected behavior

Do not apply ESM file-URL decoding to CommonJS require strings. Preserve the declared string and original source evidence, with an explicit external/unresolved outcome rather than a resolved local file. Ordinary relative require paths and static ESM file URLs should retain their current lookup behavior.

Impact and scope

Analysis invents a local dependency that the CommonJS loader does not load, despite reporting complete coverage. This undermines dependency evidence accuracy. The target is an owned local JavaScript/TypeScript directory; no target execution or native provider is needed by REA.

REA version

Source revision 3bdc8730bd98e073522bcb8ba86527be402c0cbe (package version 6.4.0).

Runtime and platform

Node.js 24.18.0, npm 11.16.0, TypeScript 7.0.2; macOS 27.0.1 arm64.

Target and artifact context

Local source directory fixture. No browser, Hopper, Ghidra or credentials.

Interface

Compiled CLI analyze-javascript-application; regression coverage also uses real stdio MCP analyze_javascript_application.

Earliest failure stage

Transport or result projection — static source dependency relationships.

Relevant output or evidence

Node require(file:///dep.cjs): exit 1, MODULE_NOT_FOUND.
Node require(URI to existing host dep.cjs): exit 1, MODULE_NOT_FOUND.
Node require(./dep.cjs): exit 0, stdout 42.
REA URI: resolution_status resolved, resolved_path dep.cjs.
CLI result reports complete coverage; repeated twice on the revision below.

Analysis or suspected cause

Source-derived: the shared resolver attempts fileUrlPath before applying the declared CommonJS loader semantics.

Originally created by @xu91102 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2057 ### Before submitting - [x] I searched open and closed issues and PRs for a related report. - [x] I removed credentials, private paths and sensitive target data. ### Area Evidence, artifacts, or reconstruction — JavaScript/TypeScript source relationships. ### Observed behavior require("file:///dep.cjs") is reported as a resolved dependency of inventoried dep.cjs. Node rejects this string with MODULE_NOT_FOUND. A second native control supplies a URI to an existing host file and is rejected too; the equivalent relative filename successfully loads 42. ### Reproduction From the repository root at the revision below, install dependencies and run `npm run build:cached`. This self-contained probe creates and removes its owned temporary fixture and compiler output: ```sh python3 - <<'PY' import json, os, shutil, subprocess, tempfile from pathlib import Path repo = Path.cwd() env = dict(os.environ, REA_LOG_LEVEL="silent") with tempfile.TemporaryDirectory(prefix="rea-repro-") as temp: fixture = Path(temp) / "source" fixture.mkdir() files = {'package.json': '{"type":"commonjs"}', 'main.cjs': 'const value = require("file:///dep.cjs"); console.log(value);', 'control.cjs': 'const value = require("./dep.cjs"); console.log(value);', 'dep.cjs': 'module.exports = 42;'} for name, text in files.items(): path = fixture / name path.parent.mkdir(parents=True, exist_ok=True) path.write_text(text + "\n") for name in ["main.cjs", "control.cjs"]: result = subprocess.run(["node", name], cwd=fixture, capture_output=True, text=True) print(name, "exit", result.returncode, "stdout", result.stdout.strip(), "MODULE_NOT_FOUND", "MODULE_NOT_FOUND" in result.stderr) target = fixture / "dep.cjs" result = subprocess.run(["node", "-e", "require(process.argv[1]);", target.as_uri()], cwd=fixture, capture_output=True, text=True) print("existing URI", "target exists", target.is_file(), "exit", result.returncode, "MODULE_NOT_FOUND", "MODULE_NOT_FOUND" in result.stderr) result = subprocess.run(["node", str(repo / "scripts/rea.mjs"), "analyze-javascript-application", str(fixture), "--format", "json"], cwd=repo, env=env, capture_output=True, text=True, check=True) graph = json.loads(result.stdout)["normalized_result"]["graph"] links = [e["properties"] for e in graph["edges"] if e["relation"] == "imports" and "module_link_kind" in e["properties"] and e["evidence"]["location"].get("value", {}).get("source") == "main.cjs"] formats = [o["properties"]["module_format"] for n in graph["nodes"] for o in n["observations"] if o.get("properties", {}).get("semantic_role") == "source-module" and o["properties"].get("path") == "main.cjs"] print("REA coverage", graph["coverage"]["status"], "format", formats) print("REA semantic imports", json.dumps(links)) PY ``` ### Expected behavior Do not apply ESM file-URL decoding to CommonJS require strings. Preserve the declared string and original source evidence, with an explicit external/unresolved outcome rather than a resolved local file. Ordinary relative require paths and static ESM file URLs should retain their current lookup behavior. ### Impact and scope Analysis invents a local dependency that the CommonJS loader does not load, despite reporting complete coverage. This undermines dependency evidence accuracy. The target is an owned local JavaScript/TypeScript directory; no target execution or native provider is needed by REA. ### REA version Source revision `3bdc8730bd98e073522bcb8ba86527be402c0cbe` (package version 6.4.0). ### Runtime and platform Node.js 24.18.0, npm 11.16.0, TypeScript 7.0.2; macOS 27.0.1 arm64. ### Target and artifact context Local source directory fixture. No browser, Hopper, Ghidra or credentials. ### Interface Compiled CLI `analyze-javascript-application`; regression coverage also uses real stdio MCP `analyze_javascript_application`. ### Earliest failure stage Transport or result projection — static source dependency relationships. ### Relevant output or evidence ```text Node require(file:///dep.cjs): exit 1, MODULE_NOT_FOUND. Node require(URI to existing host dep.cjs): exit 1, MODULE_NOT_FOUND. Node require(./dep.cjs): exit 0, stdout 42. REA URI: resolution_status resolved, resolved_path dep.cjs. CLI result reports complete coverage; repeated twice on the revision below. ``` ### Analysis or suspected cause Source-derived: the shared resolver attempts fileUrlPath before applying the declared CommonJS loader semantics.
bsakaguchi 2026-10-15 18:27:20 +00:00
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#679
No description provided.