fix: resolve CHANNEL_IDS temporal dead zone on module init (#48832)#60061
Conversation
…aw#48832) schema.ts and validation.ts imported CHANNEL_IDS from channels/registry.js, which re-exports from channels/ids.js but also imports plugins/runtime.js. When the bundler resolves this dependency graph, the re-exported CHANNEL_IDS can be undefined at the point config/validation.ts evaluates (temporal dead zone), causing 'CHANNEL_IDS is not iterable' on startup. Fix: import CHANNEL_IDS directly from channels/ids.js (the leaf module with zero heavy dependencies) and normalizeChatChannelId from channels/chat-meta.js. Fixes openclaw#48832
Greptile SummaryThis PR fixes a temporal dead zone (TDZ) crash on startup (Windows and Debian/Docker) by redirecting two imports in
Both import targets are the original definition sites, so runtime behavior is identical. The fix is minimal, targeted, and accurately described in the PR body. Confidence Score: 5/5Safe to merge — two-line targeted fix that routes imports to their original definition sites, eliminating the TDZ without any behavior change. The change is minimal and provably correct: CHANNEL_IDS was already re-exported from ids.ts through registry.ts (registry.ts line 12), and normalizeChatChannelId was re-exported from chat-meta.ts through registry.ts (lines 7 and 63). Both new imports resolve to the exact same definitions, just without the intervening registry.ts barrel that loads plugins/runtime.js at module-init time. No logic is altered, no new dependencies are introduced, and chat-meta.ts itself only depends on static bundled metadata — not the plugin runtime — so the TDZ hazard is fully eliminated. No files require special attention. Reviews (1): Last reviewed commit: "fix: import CHANNEL_IDS from leaf module..." | Re-trigger Greptile |
There was a problem hiding this comment.
Pull request overview
Updates config initialization imports to avoid pulling CHANNEL_IDS through channels/registry.js, which can trigger circular-import/TDZ failures during bundled ESM module evaluation (notably on Windows startup).
Changes:
- Switch
CHANNEL_IDSimports in config modules to the leafsrc/channels/ids.js. - Switch
normalizeChatChannelIdimport in config validation tosrc/channels/chat-meta.js(instead of thechannels/registry.jsbarrel).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/config/validation.ts | Adjusts channel-related imports to avoid the registry barrel during config validation init. |
| src/config/schema.ts | Imports CHANNEL_IDS directly from the leaf ids module to avoid registry/runtime init ordering issues. |
Comments suppressed due to low confidence (1)
src/config/validation.ts:8
- Although this file no longer imports
CHANNEL_IDS/normalizeChatChannelIdfrom../channels/registry.js, it still importsnormalizePluginsConfig/resolveEffectivePluginActivationStatefrom../plugins/config-state.js(line 7+), andsrc/plugins/config-state.tscurrently importsnormalizeChatChannelIdfrom../channels/registry.jsat module top-level. That means thechannels/registry -> plugins/runtimedependency chain can still be pulled in during config validation module initialization, so the original TDZ/circular-init startup failure may persist. Consider updatingsrc/plugins/config-state.ts(and any other early-init dependencies) to importnormalizeChatChannelIdfrom a non-runtime leaf (e.g.../channels/chat-meta.js) or moving the normalization helper into a leaf module to fully break the cycle.
import path from "node:path";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { CHANNEL_IDS } from "../channels/ids.js";
import { normalizeChatChannelId } from "../channels/chat-meta.js";
import { withBundledPluginAllowlistCompat } from "../plugins/bundled-compat.js";
import { listBundledWebSearchPluginIds } from "../plugins/bundled-web-search-ids.js";
import {
normalizePluginsConfig,
#60061) schema.ts and validation.ts imported CHANNEL_IDS from channels/registry.js, which re-exports from channels/ids.js but also imports plugins/runtime.js. When the bundler resolves this dependency graph, the re-exported CHANNEL_IDS can be undefined at the point config/validation.ts evaluates (temporal dead zone), causing 'CHANNEL_IDS is not iterable' on startup. Fix: import CHANNEL_IDS directly from channels/ids.js (the leaf module with zero heavy dependencies) and normalizeChatChannelId from channels/chat-meta.js. Fixes #48832 Co-authored-by: Brad Groux <[email protected]>
…aw#48832) (openclaw#60061) schema.ts and validation.ts imported CHANNEL_IDS from channels/registry.js, which re-exports from channels/ids.js but also imports plugins/runtime.js. When the bundler resolves this dependency graph, the re-exported CHANNEL_IDS can be undefined at the point config/validation.ts evaluates (temporal dead zone), causing 'CHANNEL_IDS is not iterable' on startup. Fix: import CHANNEL_IDS directly from channels/ids.js (the leaf module with zero heavy dependencies) and normalizeChatChannelId from channels/chat-meta.js. Fixes openclaw#48832 Co-authored-by: Brad Groux <[email protected]>
Problem
CHANNEL_IDSthrows "is not iterable" on startup (Windows, also reproduced on Debian/Docker). This is a temporal dead zone (TDZ) error.Root Cause
src/config/schema.tsandsrc/config/validation.tsimportedCHANNEL_IDSfromchannels/registry.js, which re-exports from the leaf modulechannels/ids.jsbut also importsplugins/runtime.jsandchannels/chat-meta.js. When the bundler (tsdown/ESM) resolves this dependency graph, the re-exportedCHANNEL_IDSbinding can beundefinedat the point where config modules evaluate — classic TDZ from circular or deep import chains.Fix
Import
CHANNEL_IDSdirectly fromchannels/ids.js(zero-dependency leaf module) andnormalizeChatChannelIdfromchannels/chat-meta.jsinstead of routing through the heavyweightchannels/registry.jsbarrel.Files changed:
src/config/schema.ts,src/config/validation.tsFixes #48832