openclaw - 💡(How to fix) Fix [Bug]: 2026.4.21 CLI startup regressed 8–12× — jiti.normalizeAliases O(n²) called fresh per plugin (no cross-call cache) [2 comments, 3 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#70186Fetched 2026-04-23 07:28:05
View on GitHub
Comments
2
Participants
3
Timeline
6
Reactions
0
Author
Timeline (top)
cross-referenced ×3commented ×2closed ×1

After upgrading to 2026.4.21, openclaw status, openclaw plugins list, and other CLI commands that touch the plugin loader regressed from ~instant to 12–20s wall time on a machine with 65/99 plugins loaded. CPU profile shows normalizeAliases in node_modules/jiti/dist/jiti.cjs consuming ~85% of runtime (10.3s of 12.2s total).

Root Cause

src/plugins/jiti-loader-cache.ts memoizes the per-plugin aliasMap object (via cachedPluginSdkScopedAliasMaps), but the loader still calls createJiti(filename, { alias: aliasMap, ... }) per plugin. Inside Jiti, normalizeAliases(alias) is O(n²) over the alias keys and is NOT cached across calls (only self-memoizes via a hidden symbol on its own return object, which openclaw never feeds back in). With 65 plugins × O(n²) over the SDK subpath alias map, this dominates startup.

Top of CPU profile (status command):

 self_ms    %    function
  10351  84.5%  normalizeAliases  jiti.cjs
    273   2.2%  createJiti        jiti.cjs

Related: 2026.4.20 release notes mention "reuse plugin loader alias and Jiti config resolution across repeated same-context loads" — but the fix only covered the openclaw-side aliasMap cache, not Jiti's per-createJiti normalization cost.

Fix Action

Fix / Workaround

Workaround / fix

Content-/identity-keyed cache around normalizeAliases. Local WeakMap patch (5-line diff in jiti.cjs) drops status time from 12.1s → 1.6s (≈7× faster). Prototype diff:

Code Example

time openclaw gateway status > /dev/null
# 12.1s total, 18.5s user CPU

---

self_ms    %    function
  10351  84.5%  normalizeAliases  jiti.cjs
    273   2.2%  createJiti        jiti.cjs

---

var __jitiNAWM = globalThis.__jitiNAWM ||
                 (globalThis.__jitiNAWM = new WeakMap());
function normalizeAliases(e) {
  if (e[pt]) return e;
  var c = __jitiNAWM.get(e); if (c) return c;
  // ... existing body ...
  __jitiNAWM.set(e, t);
  return Object.defineProperty(t, pt, {value:!0,enumerable:!1}), t;
}
RAW_BUFFERClick to expand / collapse

Summary

After upgrading to 2026.4.21, openclaw status, openclaw plugins list, and other CLI commands that touch the plugin loader regressed from ~instant to 12–20s wall time on a machine with 65/99 plugins loaded. CPU profile shows normalizeAliases in node_modules/jiti/dist/jiti.cjs consuming ~85% of runtime (10.3s of 12.2s total).

Environment

  • openclaw 2026.4.21 (f788c88)
  • macOS 26.4.1 arm64, node 25.8.1
  • 65/99 plugins loaded (most are bundled providers)

Repro

time openclaw gateway status > /dev/null
# 12.1s total, 18.5s user CPU

Root cause

src/plugins/jiti-loader-cache.ts memoizes the per-plugin aliasMap object (via cachedPluginSdkScopedAliasMaps), but the loader still calls createJiti(filename, { alias: aliasMap, ... }) per plugin. Inside Jiti, normalizeAliases(alias) is O(n²) over the alias keys and is NOT cached across calls (only self-memoizes via a hidden symbol on its own return object, which openclaw never feeds back in). With 65 plugins × O(n²) over the SDK subpath alias map, this dominates startup.

Top of CPU profile (status command):

 self_ms    %    function
  10351  84.5%  normalizeAliases  jiti.cjs
    273   2.2%  createJiti        jiti.cjs

Related: 2026.4.20 release notes mention "reuse plugin loader alias and Jiti config resolution across repeated same-context loads" — but the fix only covered the openclaw-side aliasMap cache, not Jiti's per-createJiti normalization cost.

Workaround / fix

Content-/identity-keyed cache around normalizeAliases. Local WeakMap patch (5-line diff in jiti.cjs) drops status time from 12.1s → 1.6s (≈7× faster). Prototype diff:

var __jitiNAWM = globalThis.__jitiNAWM ||
                 (globalThis.__jitiNAWM = new WeakMap());
function normalizeAliases(e) {
  if (e[pt]) return e;
  var c = __jitiNAWM.get(e); if (c) return c;
  // ... existing body ...
  __jitiNAWM.set(e, t);
  return Object.defineProperty(t, pt, {value:!0,enumerable:!1}), t;
}

Better fix lives in openclaw: wrap createJiti in getCachedPluginJitiLoader so identical (filename, aliasMap, tryNative) triples share the Jiti instance cross-plugin, or pass the normalized aliasMap in and have Jiti short-circuit via its existing pt marker.

Related

  • #13810 (completion slow) — same root cause path
  • #62364 (slow startup with multiple providers) — symptom overlap

extent analysis

TL;DR

Implement a content-/identity-keyed cache around normalizeAliases in jiti.cjs to significantly reduce the startup time of openclaw CLI commands.

Guidance

  • Apply the proposed 5-line diff patch in jiti.cjs to introduce a WeakMap cache, which has been shown to drop the status time from 12.1s to 1.6s.
  • Consider implementing a better fix in openclaw by wrapping createJiti in getCachedPluginJitiLoader to share Jiti instances across identical plugin loads.
  • Verify the fix by running the time openclaw gateway status > /dev/null command and checking the execution time.
  • Be aware that this fix may not be applicable to all environments or versions, and further testing may be necessary to ensure compatibility.

Example

The proposed patch in jiti.cjs can be applied as follows:

var __jitiNAWM = globalThis.__jitiNAWM ||
                 (globalThis.__jitiNAWM = new WeakMap());
function normalizeAliases(e) {
  if (e[pt]) return e;
  var c = __jitiNAWM.get(e); if (c) return c;
  //... existing body...
  __jitiNAWM.set(e, t);
  return Object.defineProperty(t, pt, {value:!0,enumerable:!1}), t;
}

Notes

The provided patch is a local fix and may not be suitable for all environments. A more robust solution may involve modifying the openclaw code to cache the normalized alias map.

Recommendation

Apply the workaround patch in jiti.cjs as a temporary fix, and consider implementing a more robust solution in openclaw to cache the normalized alias map. This will provide a significant reduction in startup time for openclaw CLI commands.

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