Skip to content

fix: handle lazy initialization and circular dependencies#229

Merged
timfish merged 3 commits intonodejs:mainfrom
BridgeAR:BridgeAR/2026-01-15-fix-circular
Jan 20, 2026
Merged

fix: handle lazy initialization and circular dependencies#229
timfish merged 3 commits intonodejs:mainfrom
BridgeAR:BridgeAR/2026-01-15-fix-circular

Conversation

@BridgeAR
Copy link
Member

When finding circular dependencies or undefined exports, retry loading with a delay. That way most hooking will work as expected.

It uses a backoff time and has a small finite retry number. There is no guarantee that an async initialization will be detected, but it should match pretty much all cases known to fail so far.

In addition, we use the parser for Node.js 16+ now. That was needed to make the circular structure fix from Node.js 16 on.

Fixes: #227
Fixes: #32

When finding circular dependencies or undefined exports, retry
loading with a delay. That way most hooking will work as expected.

It uses a backoff time and has a small finite retry number.
There is no guarantee that an async initialization will be detected,
but it should match pretty much all cases known to fail so far.

In addition, we use the parser for Node.js 16+ now. That was needed
to make the circular structure fix from Node.js 16 on.

Fixes: nodejs#227
Fixes: nodejs#32
@BridgeAR BridgeAR force-pushed the BridgeAR/2026-01-15-fix-circular branch from 3e8b14d to 5ef6acc Compare January 19, 2026 12:09
@BridgeAR BridgeAR marked this pull request as ready for review January 19, 2026 12:09
@timfish timfish requested a review from jsumners-nr January 20, 2026 15:32
Comment on lines +6 to +15
// Defer initialization with a timeout. This means that by the time an `import()`
// resolves, native ESM will have initialized the binding, but IITM's wrapper may
// have snapshotted it too early.
setTimeout(() => {
RunTree = class RunTree {
constructor () {
this.ok = true
}
}
}, 5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this will be fragile with respect to timing? Would a setImmediate or nextTick be more robust?

Copy link
Member Author

@BridgeAR BridgeAR Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the delay of a total of ~61 ms should suffice to not be flaky (we retry with a single millisecond, afterwards once more with 10 and afterwards with 50).

@timfish timfish merged commit d1421dc into nodejs:main Jan 20, 2026
51 checks passed
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.

Circular re-export "is not a constructor" Loader fails when circular dependencies exist within an application

3 participants