test: avoid TLA self-cycle in bun-main dynamic-import test#29738
Conversation
bun:main statically imports the entry, so awaiting import("bun:main")
at the entry's top level is a TLA self-cycle that never resolves under
the new JSC module loader (#29393). Prior to that rewrite the loader
broke the cycle early, which is why this passed when #29719 landed.
Switch the entry from `await import("bun:main")` to
`import("bun:main").then(...)` so the entry finishes synchronously,
bun:main finishes, and the import promise resolves on the next tick.
The preload and --hot tests are unaffected.
|
Updated 11:20 PM PT - Apr 25th, 2026
❌ @dylan-conway, your commit ca81de4 has 3 failures in
🧪 To try this PR locally: bunx bun-pr 29738That installs a local version of the PR into your bun-29738 --bun |
There was a problem hiding this comment.
LGTM — test-only deflake, well-reasoned fix for the TLA self-cycle.
Extended reasoning...
Overview
This PR modifies a single test fixture in test/js/bun/resolve/bun-main-entry-point.test.ts. It rewrites the embedded entry.mjs script in the "dynamic import('bun:main')" test case to use import("bun:main").then(...) instead of top-level await import("bun:main"), avoiding a TLA self-cycle deadlock that surfaced after the WebKit module-loader rewrite (#29393). The assertions are unchanged; an explicit rejection handler was added that prints the error and exits 1.
Security risks
None. This is a test-only change to an embedded fixture string. No production/runtime code, no auth/crypto/permissions, no new dependencies.
Level of scrutiny
Low. The change is small (~15 lines net), mechanical, and confined to test fixture code. The reasoning is clearly documented in both the PR description and an inline comment, and the author verified 20 consecutive passes on Windows plus confirmed the test still catches the original alias regression under USE_SYSTEM_BUN=1.
Other factors
- The assertion semantics are preserved: the same checks run inside the
.then()fulfillment handler, and the outer test still assertsstdout: "OK\n", empty stderr, andexitCode: 0. If an assertion throws inside the handler it becomes an unhandled rejection, which will produce non-empty stderr / non-zero exit and correctly fail the outer expect. - The other two tests in the file (preload and
--hot) are untouched, matching the PR description's note that they aren't inbun:main's dep graph. - No prior reviewer comments or outstanding feedback on the timeline; bug-hunting system found no issues.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughReplaced a top-level Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/js/bun/resolve/bun-main-entry-point.test.ts`:
- Around line 29-42: The import("bun:main").then(...) call currently passes a
rejection handler as the second .then argument but assertion errors thrown
inside the fulfillment callback (the function that inspects m using
Symbol.toStringTag and Object.keys) will bypass that and won't trigger the
process.exit(1) path; fix by chaining a .catch() after the .then to log the
error with console.error(String(e)) and call process.exit(1) so any thrown
errors from the fulfillment handler are handled and cause the test to fail.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3097c256-f9ef-4f30-9575-3b097705514e
📒 Files selected for processing (1)
test/js/bun/resolve/bun-main-entry-point.test.ts
There was a problem hiding this comment.
LGTM — straightforward test-fixture deflake, and the .catch() feedback is already addressed.
Extended reasoning...
Overview
This PR touches a single test file, test/js/bun/resolve/bun-main-entry-point.test.ts, and only modifies the inline entry.mjs fixture string for one test case. It replaces const m = await import("bun:main") at the entry's top level with import("bun:main").then(...).catch(...), plus an explanatory comment. The assertion logic inside is byte-for-byte identical to before; only the control-flow wrapper changed. The other two tests in the file (preload and --hot) are untouched.
Security risks
None. This is a test-only change to a fixture string that runs in a spawned subprocess inside a temp dir. No runtime, resolver, or production code is modified.
Level of scrutiny
Low. The PR description gives a precise and correct explanation: bun:main statically imports the entry, so top-level await import("bun:main") from the entry creates a TLA self-cycle that per spec never settles, and the post-#29393 module loader now (correctly) honors that. Dropping the top-level await lets entry.mjs finish synchronously so bun:main can settle and the dynamic import resolves on the next microtask. The .then().catch() shape ensures both import rejection and assertion throws inside the fulfillment handler hit process.exit(1), so regressions still fail the outer exitCode: 0 / stdout: "OK\n" assertion. The change is mechanical and self-contained.
Other factors
- No bugs flagged by the bug-hunting system.
- CodeRabbit's one nit (use chained
.catch()instead of the second.thenarg so assertion throws are caught) was addressed in ca81de4 and the final diff reflects it; that thread is resolved. - Author verified 3/3 pass over 20 consecutive Windows runs, and confirmed the test still fails on an unfixed
bun(so it hasn't been neutered). - The robobun ❌ on build #48033 is the generic CI status comment; given this PR only edits one test fixture string, any unrelated failures there are not attributable to this change.
…9738) Follow-up to oven-sh#29719. `bun:main` statically imports the entry file, so `await import("bun:main")` at the entry's top level is a TLA self-cycle: `bun:main` waits for `entry.mjs` (async dep), and `entry.mjs` waits for `bun:main`'s evaluation promise. Per spec that promise never settles. The old JSC module loader broke these cycles early, which is why oven-sh#29719 passed locally (tested against `892042c2`, pre-oven-sh#29393). After oven-sh#29393 (WebKit module-loader rewrite) the loader correctly leaves the promise unsettled, so the test now hangs and times out at 90s — see build 48023 (debian-asan, win x64, win x64-baseline). Fix: drop the top-level `await` and use `import("bun:main").then(...)` so `entry.mjs` finishes synchronously, `bun:main` finishes, and the import resolves on the next microtask. The preload and `--hot` tests are unaffected (preload isn't in `bun:main`'s dep graph). Note: this also surfaced that Bun now hangs forever on any unsettled-TLA cycle instead of exiting 13 like Node — separate PR coming for that. ## How did you verify your code works? - `bun bd test test/js/bun/resolve/bun-main-entry-point.test.ts` — 3 pass, 20 consecutive runs on Windows - `USE_SYSTEM_BUN=1 bun test ...` — 2 fail (still catches the alias bug on unfixed bun)
Follow-up to #29719.
bun:mainstatically imports the entry file, soawait import("bun:main")at the entry's top level is a TLA self-cycle:bun:mainwaits forentry.mjs(async dep), andentry.mjswaits forbun:main's evaluation promise. Per spec that promise never settles.The old JSC module loader broke these cycles early, which is why #29719 passed locally (tested against
892042c2, pre-#29393). After #29393 (WebKit module-loader rewrite) the loader correctly leaves the promise unsettled, so the test now hangs and times out at 90s — see build 48023 (debian-asan, win x64, win x64-baseline).Fix: drop the top-level
awaitand useimport("bun:main").then(...)soentry.mjsfinishes synchronously,bun:mainfinishes, and the import resolves on the next microtask. The preload and--hottests are unaffected (preload isn't inbun:main's dep graph).Note: this also surfaced that Bun now hangs forever on any unsettled-TLA cycle instead of exiting 13 like Node — separate PR coming for that.
How did you verify your code works?
bun bd test test/js/bun/resolve/bun-main-entry-point.test.ts— 3 pass, 20 consecutive runs on WindowsUSE_SYSTEM_BUN=1 bun test ...— 2 fail (still catches the alias bug on unfixed bun)