Skip to content

fix(core): evaluate pre-instantiated module in lazy_load_esm_module#33973

Merged
bartlomieju merged 1 commit into
mainfrom
fix/lazy-load-esm-evaluate-pre-instantiated
May 12, 2026
Merged

fix(core): evaluate pre-instantiated module in lazy_load_esm_module#33973
bartlomieju merged 1 commit into
mainfrom
fix/lazy-load-esm-evaluate-pre-instantiated

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

The early-return path of lazy_load_esm_module handed back a module's
namespace without checking the module's evaluation status. When the
module was already registered in the module map (e.g. as a static
import in the caller's bundle that V8 instantiated during the link
phase) but V8 hadn't reached it yet in DFS post-order, the namespace's
export const bindings were in the temporal dead zone — so any caller
that destructured the lazy namespace at module evaluation time saw
Cannot access 'X' before initialization. The fix evaluates the
module before returning the namespace when its status is
Instantiated, mirroring the existing logic in
lazy_load_es_module_with_code.

The user-visible symptom was gemini-cli failing at startup with
Cannot access 'AsyncResource' before initialization. The recent
events_esm.ts wrapper destructures EventEmitterAsyncResource, whose
lazy getter loads node:async_hooks — itself a sibling static import
elsewhere in the bundle, so it had been instantiated but not yet
evaluated.

Fixes #33940

When a lazy-loaded ESM module is already registered in the module map
(e.g. as a static import in the user's bundle that V8 instantiated
during the link phase), the early-return path handed back the namespace
without checking the module's evaluation status. If V8 hadn't reached
that module yet in its DFS post-order evaluation, the namespace's
`export const` bindings were in the temporal dead zone — surfacing as
`Cannot access 'X' before initialization` from any caller that
destructures the lazy namespace at module evaluation time.

Surfaced through gemini-cli: events_esm.ts destructures
`EventEmitterAsyncResource`, whose lazy getter loads node:async_hooks,
which is a sibling static import elsewhere in the bundle.

Fixes #33940
@bartlomieju
bartlomieju merged commit a72f4c5 into main May 12, 2026
267 of 270 checks passed
@bartlomieju
bartlomieju deleted the fix/lazy-load-esm-evaluate-pre-instantiated branch May 12, 2026 12:52
littledivy pushed a commit to crowlKats/deno that referenced this pull request Jun 10, 2026
…enoland#33973)

The early-return path of `lazy_load_esm_module` handed back a module's
namespace without checking the module's evaluation status. When the
module was already registered in the module map (e.g. as a static
import in the caller's bundle that V8 instantiated during the link
phase) but V8 hadn't reached it yet in DFS post-order, the namespace's
`export const` bindings were in the temporal dead zone — so any caller
that destructured the lazy namespace at module evaluation time saw
`Cannot access 'X' before initialization`. The fix evaluates the
module before returning the namespace when its status is
`Instantiated`, mirroring the existing logic in
`lazy_load_es_module_with_code`.

The user-visible symptom was gemini-cli failing at startup with
`Cannot access 'AsyncResource' before initialization`. The recent
events_esm.ts wrapper destructures `EventEmitterAsyncResource`, whose
lazy getter loads `node:async_hooks` — itself a sibling static import
elsewhere in the bundle, so it had been instantiated but not yet
evaluated.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot access 'AsyncResource' before initialization

2 participants