Summary
All bundled channel plugins fail to load with RangeError: Maximum call stack size exceeded during gateway startup. The stack overflow occurs in jiti's recursive module evaluator (eval_evalModule → jitiRequire chain), which creates a deeply nested call stack when loading compiled dist chunks. By the time downstream dependencies (ajv, highlight.js, etc.) initialize, the call stack is exhausted.
Workaround: Set OPENCLAW_SKIP_CHANNEL_PLUGINS=1 environment variable to bypass channel plugin loading entirely. This has been added to start-openclaw.ps1 as a temporary measure.
Root Cause Analysis
The Loading Chain
Each channel extension loads through jiti via dist-runtime/extensions/<channel>/index.js → dist/extensions/<channel>/index.js, which triggers a deep dependency chain:
channel extension → channel-core → extension-shared → runtime → command-secret-gateway → call → method-scopes → (ajv/highlight.js)
Each jiti step adds multiple frames (jitiRequire → eval_evalModule → anonymous wrapper). By the time the chain reaches modules that do significant initialization work (ajv schema compilation, highlight.js loading), the stack is exhausted.
Stack Trace
[openclaw] Failed to start CLI: RangeError: Maximum call stack size exceeded
at schemaHasRulesForType (node_modules/ajv/dist/compile/validate/applicability.js:6:39)
...
at method-scopes-XXXX.js:1884:35 (ajv.compile at module level)
at ModuleJobSync.runSync (node:internal/modules/esm/module_job)
at loadESMFromCJS (node:internal/modules/cjs/loader)
at jitiRequire → eval_evalModule (repeated ~7 levels deep)
at dist/extensions/googlechat/index.js
Contributing Factors
- ~70+
ajv.compile() calls at module level in gateway/protocol/index.ts — each adds recursive stack frames for schema walking
- jiti's recursive CJS↔ESM bridge — each module in the chain adds 2-3 stack frames
- Transitive dependency depth — channel extensions pull in the entire gateway protocol module through shared chunks
Changes Already Applied
1. Lazy ajv compilation (src/gateway/protocol/index.ts)
Replaced ~70 eager ajv.compile() calls with lazyCompile() wrappers that defer compilation to first use. This prevents ajv from consuming stack during module initialization.
2. Strip $schema from bundled schemas (src/plugins/bundled-plugin-metadata.ts)
The runtime metadata loader was passing schemas with $schema: "http://json-schema.org/draft-07/schema#" to ajv, causing it to try compiling the self-referential JSON Schema meta-schema. Now stripped at collection time.
3. validateSchema: false on all ajv instances
Added to both schema-validator.ts and gateway/protocol/index.ts to prevent ajv from validating schemas against the meta-schema.
4. Regenerated bundled-channel-config-metadata.generated.ts
The $schema property is now stripped by stripSchemaProperty() in the generation script.
5. OPENCLAW_SKIP_CHANNEL_PLUGINS env var bypass (src/channels/plugins/bundled.ts)
When set, skips loadGeneratedBundledChannelEntries() entirely, returning an empty array.
What Still Needs to Be Done
Files Modified
src/gateway/protocol/index.ts — lazy ajv compilation
src/plugins/schema-validator.ts — validateSchema: false
src/plugins/bundled-plugin-metadata.ts — strip $schema from runtime schemas
src/channels/plugins/bundled.ts — OPENCLAW_SKIP_CHANNEL_PLUGINS bypass
scripts/generate-bundled-channel-config-metadata.ts — stripSchemaProperty() helper
start-openclaw.ps1 — set OPENCLAW_SKIP_CHANNEL_PLUGINS=1
src/config/bundled-channel-config-metadata.generated.ts — regenerated without $schema
Environment
- Node.js v22.18.0
- Windows 11 Pro
- Default stack size (~1MB)
Summary
All bundled channel plugins fail to load with
RangeError: Maximum call stack size exceededduring gateway startup. The stack overflow occurs in jiti's recursive module evaluator (eval_evalModule→jitiRequirechain), which creates a deeply nested call stack when loading compiled dist chunks. By the time downstream dependencies (ajv, highlight.js, etc.) initialize, the call stack is exhausted.Workaround: Set
OPENCLAW_SKIP_CHANNEL_PLUGINS=1environment variable to bypass channel plugin loading entirely. This has been added tostart-openclaw.ps1as a temporary measure.Root Cause Analysis
The Loading Chain
Each channel extension loads through jiti via
dist-runtime/extensions/<channel>/index.js→dist/extensions/<channel>/index.js, which triggers a deep dependency chain:Each jiti step adds multiple frames (
jitiRequire→eval_evalModule→ anonymous wrapper). By the time the chain reaches modules that do significant initialization work (ajv schema compilation, highlight.js loading), the stack is exhausted.Stack Trace
Contributing Factors
ajv.compile()calls at module level ingateway/protocol/index.ts— each adds recursive stack frames for schema walkingChanges Already Applied
1. Lazy ajv compilation (
src/gateway/protocol/index.ts)Replaced ~70 eager
ajv.compile()calls withlazyCompile()wrappers that defer compilation to first use. This prevents ajv from consuming stack during module initialization.2. Strip
$schemafrom bundled schemas (src/plugins/bundled-plugin-metadata.ts)The runtime metadata loader was passing schemas with
$schema: "http://json-schema.org/draft-07/schema#"to ajv, causing it to try compiling the self-referential JSON Schema meta-schema. Now stripped at collection time.3.
validateSchema: falseon all ajv instancesAdded to both
schema-validator.tsandgateway/protocol/index.tsto prevent ajv from validating schemas against the meta-schema.4. Regenerated
bundled-channel-config-metadata.generated.tsThe
$schemaproperty is now stripped bystripSchemaProperty()in the generation script.5.
OPENCLAW_SKIP_CHANNEL_PLUGINSenv var bypass (src/channels/plugins/bundled.ts)When set, skips
loadGeneratedBundledChannelEntries()entirely, returning an empty array.What Still Needs to Be Done
import()for bundled channel loading instead of jiti's CJS bridgedist-runtimeproxy files can use dynamicimport()instead of re-exports--stack-sizeneededOPENCLAW_SKIP_CHANNEL_PLUGINSworkaround once the underlying jiti issue is resolvedFiles Modified
src/gateway/protocol/index.ts— lazy ajv compilationsrc/plugins/schema-validator.ts—validateSchema: falsesrc/plugins/bundled-plugin-metadata.ts— strip$schemafrom runtime schemassrc/channels/plugins/bundled.ts—OPENCLAW_SKIP_CHANNEL_PLUGINSbypassscripts/generate-bundled-channel-config-metadata.ts—stripSchemaProperty()helperstart-openclaw.ps1— setOPENCLAW_SKIP_CHANNEL_PLUGINS=1src/config/bundled-channel-config-metadata.generated.ts— regenerated without$schemaEnvironment