openclaw - ✅(Solved) Fix Feishu channel crash on Windows: dual jiti/ESM module instance splits runtime store [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#61614Fetched 2026-04-08 02:56:49
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

Error Message

Error: Feishu runtime not initialized at extensions/feishu/src/monitor.account.ts:398

Root Cause

Commit 3a4b96bf ("fix: normalize plugin SDK aliases on Windows") added a blanket if (process.platform === "win32") return false guard to shouldPreferNativeJiti(). This forces jiti to evaluate all dist .js chunks via vm.runInThisContext in its own internal cache, rather than delegating to Node's native ESM loader.

When the Feishu plugin later does a dynamic import("../../monitor-BnkfuO_x.js"), that import() expression escapes from jiti's evaluated context to Node's native ESM loader. Node has never seen runtime-BAUYLedo.js (jiti loaded it, not Node), so it creates a second, independent module instance with its own createPluginRuntimeStore closure.

Result:

  • setFeishuRuntime(api.runtime) writes to jiti's closure (during plugin register())
  • getFeishuRuntime() reads from Node ESM's closure (when monitorFeishuProvider runs)
  • The ESM closure's runtime is still null → throws "Feishu runtime not initialized"

This only affects Windows because shouldPreferNativeJiti returns true for .js files on macOS/Linux, keeping both paths on the same native ESM module identity.

Fix Action

Fix

Remove the win32 guard from shouldPreferNativeJiti(). The actual Windows issue (backslash paths in jiti alias maps) was already solved by normalizeJitiAliasTargetPath() in the same commit. The tryNative disable was unnecessary and broke module identity.

PR fix notes

PR #61618: fix(win): re-enable native jiti loading for dist .js to prevent dual module instances

Description (problem / solution / changelog)

Summary

  • Fixes #61614 — Feishu channel crash loop on Windows due to dual jiti/ESM module identity for the plugin runtime store
  • Removes the blanket win32 guard from shouldPreferNativeJiti() that was introduced in 3a4b96bf, which forced jiti to evaluate all dist .js chunks via vm.runInThisContext instead of Node's native ESM loader
  • The actual Windows issue (backslash paths in jiti alias maps) is already handled by normalizeJitiAliasTargetPath()

Root Cause

When tryNative is false on Windows, jiti creates its own module cache separate from Node's native ESM registry. Dynamic import() inside jiti-evaluated code escapes back to Node's ESM loader, creating a second instance of runtime-BAUYLedo.js with its own createPluginRuntimeStore closure. setFeishuRuntime() writes to jiti's closure during register(), but getFeishuRuntime() reads from the ESM closure when the monitor runs — which is still null.

Testing

  • pnpm test src/plugins/sdk-alias.test.ts — 27/27 pass
  • pnpm test src/plugins/loader.test.ts — 134/134 pass
  • pnpm build — clean
  • Gateway startup verified: all 3 Feishu accounts start without "Feishu runtime not initialized" error

Changed files

  • src/plugins/sdk-alias.test.ts (modified, +7/-3)
  • src/plugins/sdk-alias.ts (modified, +7/-3)

Code Example

Error: Feishu runtime not initialized
    at extensions/feishu/src/monitor.account.ts:398
RAW_BUFFERClick to expand / collapse

Bug

On Windows, the Feishu channel plugin crashes on every gateway startup with:

Error: Feishu runtime not initialized
    at extensions/feishu/src/monitor.account.ts:398

Both main and bot2 Feishu accounts fail, triggering exponential-backoff restart loops that never recover.

Root Cause

Commit 3a4b96bf ("fix: normalize plugin SDK aliases on Windows") added a blanket if (process.platform === "win32") return false guard to shouldPreferNativeJiti(). This forces jiti to evaluate all dist .js chunks via vm.runInThisContext in its own internal cache, rather than delegating to Node's native ESM loader.

When the Feishu plugin later does a dynamic import("../../monitor-BnkfuO_x.js"), that import() expression escapes from jiti's evaluated context to Node's native ESM loader. Node has never seen runtime-BAUYLedo.js (jiti loaded it, not Node), so it creates a second, independent module instance with its own createPluginRuntimeStore closure.

Result:

  • setFeishuRuntime(api.runtime) writes to jiti's closure (during plugin register())
  • getFeishuRuntime() reads from Node ESM's closure (when monitorFeishuProvider runs)
  • The ESM closure's runtime is still null → throws "Feishu runtime not initialized"

This only affects Windows because shouldPreferNativeJiti returns true for .js files on macOS/Linux, keeping both paths on the same native ESM module identity.

Impact

  • All Feishu channel accounts fail to start on Windows
  • The restart loop runs indefinitely with exponential backoff (5s → 300s)
  • Affects any channel plugin that uses createPluginRuntimeStore + dynamic import() in the dist chunk graph

Fix

Remove the win32 guard from shouldPreferNativeJiti(). The actual Windows issue (backslash paths in jiti alias maps) was already solved by normalizeJitiAliasTargetPath() in the same commit. The tryNative disable was unnecessary and broke module identity.

extent analysis

TL;DR

Remove the win32 guard from shouldPreferNativeJiti() to fix the Feishu channel plugin crash on Windows.

Guidance

  • Identify the problematic commit (3a4b96bf) and review the changes made to shouldPreferNativeJiti().
  • Verify that removing the win32 guard resolves the issue by testing the Feishu channel plugin on Windows.
  • Consider backporting the fix to affected versions or releasing a new version with the corrected shouldPreferNativeJiti() function.
  • Test other channel plugins that use createPluginRuntimeStore and dynamic import() to ensure they are not affected by the same issue.

Example

No code snippet is provided as the issue is clearly described and the fix is straightforward.

Notes

This fix assumes that the normalizeJitiAliasTargetPath() function correctly handles Windows path issues, as stated in the issue. If this is not the case, additional changes may be necessary.

Recommendation

Apply the workaround by removing the win32 guard from shouldPreferNativeJiti(), as this directly addresses the root cause of the issue and has been verified to resolve the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING