Skip to content

Fix resolver panic on Windows drive-letter specifiers on POSIX - #32017

Open
robobun wants to merge 3 commits into
mainfrom
farm/1b5fc489/fix-drive-letter-join-panic
Open

Fix resolver panic on Windows drive-letter specifiers on POSIX#32017
robobun wants to merge 3 commits into
mainfrom
farm/1b5fc489/fix-drive-letter-join-panic

Conversation

@robobun

@robobun robobun commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Fixes #32016

Repro

On Linux or macOS, with a node_modules directory in cwd or any ancestor (or a tsconfig.json with baseUrl):

await import.meta.resolve("C:/", import.meta.url);
panic: cannot resolve DirInfo for non-absolute path: C:/

The same panic is reachable through require.resolve("C:/"), Bun.resolveSync("C:/", dir), and dynamic import("C:/"), with any X:/ or X:\ shaped specifier.

Cause

On POSIX, C:/ is not an absolute path, so the resolver correctly classifies it as a bare package specifier and enters the node_modules search, joining [dir, "node_modules", import_path] with the loose-platform join. The loose platform's is_absolute accepts Windows drive paths on any host, so the join's reset loop in _join_abs_string_buf (src/paths/resolve_path.rs) adopted C:/ as a new join root and returned it verbatim. dir_info_cached then asserts host-native absoluteness (src/resolver/resolver.rs:4194) and panics. The assert is a plain assert!, so release builds crash too, making any import specifier shaped like a drive path a DoS.

The tsconfig baseUrl/paths joins and the package.json main/browser field joins funnel through the same primitive and panic the same way (import("C:/nope") with "baseUrl": "." reproduces it without any node_modules).

Fix

In the POSIX branch of _join_abs_string_buf, a part resets the join root only when it starts with a path separator. A drive-letter part cannot be a usable root on a POSIX host (the result would not be absolute, violating the join's contract), so it now joins as an ordinary relative component. Resolution then fails with a catchable "Cannot find module" error, exactly like the no-node_modules case, and a directory literally named C: under node_modules is findable, matching Node's CJS loader (path.resolve(nmDir, "C:/x") lands inside node_modules).

The Windows-host join is dispatched to _join_abs_string_buf_windows before this loop and is unchanged; drive letters are real roots there. POSIX-absolute parts (env-derived cache dirs, NODE_PATH entries, absolute specifiers) still reset as before.

Verification

Two tests added to test/js/bun/resolve/resolve-error.test.ts (POSIX-only; drive paths are genuinely absolute on Windows):

  • node_modules search: import.meta.resolve / require.resolve / Bun.resolveSync / import() for C:/, C:\, D:\foo, c:/x all throw ERR_MODULE_NOT_FOUND / MODULE_NOT_FOUND, plus a positive case resolving node_modules/C:/real.js
  • tsconfig baseUrl join: import("C:/nope") with "baseUrl": "." throws instead of panicking

Both tests panic the child process on the unfixed build (USE_SYSTEM_BUN=1) and pass with the fix. The full test/js/bun/resolve/ suite, test/bundler/esbuild/tsconfig.test.ts, test/bundler/esbuild/packagejson.test.ts, and test/bundler/resolver/ pass (the only failures are three pre-existing stress-test timeouts that fail identically without this diff).

…POSIX

On POSIX hosts a specifier like "C:/" is not an absolute path, so the
resolver treats it as a bare package specifier. The loose-platform join
used for the node_modules search, tsconfig baseUrl/paths, and
package.json field joins still recognized "C:/" as Windows-absolute and
adopted it as the join root, returning a path that is not absolute on
the host. That tripped the assert in dir_info_cached:

    panic: cannot resolve DirInfo for non-absolute path: C:/

In the POSIX branch of _join_abs_string_buf, a part now resets the join
root only when it starts with a path separator. Drive-letter parts join
as ordinary relative components, so resolution fails with a catchable
"Cannot find module" error, and a directory literally named "C:" under
node_modules remains resolvable, matching Node's CJS loader.

Fixes #32016
@robobun

robobun commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 3:05 AM PT - Jun 10th, 2026

@robobun, your commit 612353c has some failures in Build #61695 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 32017

That installs a local version of the PR into your bun-32017 executable, so you can run:

bun-32017 --bun

@github-actions github-actions Bot added the claude label Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0b73cd1e-18b3-4c51-b1ab-14edd38e4bce

📥 Commits

Reviewing files that changed from the base of the PR and between a988615 and cba2182.

📒 Files selected for processing (2)
  • src/paths/resolve_path.rs
  • test/js/bun/resolve/resolve-error.test.ts

Walkthrough

This PR fixes a panic in import.meta.resolve() when encountering Windows-style drive-letter paths (e.g., C:/) on POSIX systems. The fix refines path joining logic to distinguish between absolute paths that start with a separator versus drive-letter absolute paths, preventing the latter from incorrectly resetting the join root. Tests verify the corrected behavior.

Changes

Drive-letter path resolution

Layer / File(s) Summary
Path joining logic fix for absolute parts
src/paths/resolve_path.rs
In _join_abs_string_buf, resetting cwd during path joins now requires both is_absolute() and a leading separator check, preventing drive-letter absolute parts from being treated as filesystem roots while allowing separator-rooted absolutes to reset the join point.
Drive-letter path resolution tests on POSIX
test/js/bun/resolve/resolve-error.test.ts
Imports bunExe and isWindows from harness; adds a POSIX-only test suite confirming that drive-letter-like specifiers (C:/, C:\, D:\\foo, c:/x) are treated as bare package names, emit catchable module-not-found errors, and do not reset to fake filesystem roots. A second test repeats assertions through tsconfig baseUrl joins.

Possibly related issues

  • oven-sh/bun#30839 — Related path normalization and resolver handling of platform-specific path forms; the fix to _join_abs_string_buf directly addresses drive-letter path handling that was causing resolver panics.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: fixing a resolver panic triggered by Windows drive-letter specifiers on POSIX systems.
Description check ✅ Passed The PR description comprehensively covers the issue, root cause analysis, implemented fix, and verification with multiple tests, but lacks explicit "How did you verify your code works?" section structure from the template.
Linked Issues check ✅ Passed The PR successfully addresses all objectives from issue #32016: eliminates the panic for drive-letter specifiers on POSIX, produces catchable module-not-found errors, preserves Node.js-compatible behavior for literal 'C:' directories, and includes comprehensive test coverage validating the fix.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to fixing the reported panic: the resolver logic change in src/paths/resolve_path.rs targets the root cause, and test additions in test/js/bun/resolve/resolve-error.test.ts validate the fix without introducing unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@robobun

robobun commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

CI status for the latest build (61695, after main was merged in with the #32042 bunx skip): 284 jobs passed with zero test failures, including this PR's new tests on every lane that ran (all Linux glibc/musl/baseline/asan, all Windows, macOS 26 aarch64 and 14 x64). The only red is the two darwin-14-aarch64 test jobs, which expired in queue without ever running (agent capacity; the same pool stalled the previous build). Nothing left to fix in the diff; those two jobs just need a retry from the Buildkite UI once agents are available.

@robobun

robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Status check against current main (165dc9f):

So this PR is no longer needed for the crash; what remains is the drive-letter-as-bare-specifier join behavior. The src hunk still applies cleanly to main. Leaving open for a maintainer to decide whether that behavior is wanted on its own.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bun panics with cannot resolve DirInfo for non-absolute path: C:/ during import.meta.resolve()

1 participant