openclaw - ✅(Solved) Fix plugins: normalizePluginsConfig drops slots.contextEngine, causing false "plugins.allow is empty" warning [4 pull requests, 2 comments, 2 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#64170Fetched 2026-04-11 06:16:03
View on GitHub
Comments
2
Participants
2
Timeline
18
Reactions
0
Participants
Timeline (top)
referenced ×7cross-referenced ×6commented ×2closed ×1

normalizePluginsConfigWithResolver() preserves plugins.slots.memory but silently drops plugins.slots.contextEngine from the normalized plugin config. That causes slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics.

One visible symptom is a false warning from warnWhenAllowlistIsOpen() saying plugins.allow is empty even when the on-disk config has a populated allowlist and the context engine was selected via plugins.slots.contextEngine.

Root Cause

normalizePluginsConfigWithResolver() preserves plugins.slots.memory but silently drops plugins.slots.contextEngine from the normalized plugin config. That causes slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics.

One visible symptom is a false warning from warnWhenAllowlistIsOpen() saying plugins.allow is empty even when the on-disk config has a populated allowlist and the context engine was selected via plugins.slots.contextEngine.

Fix Action

Fixed

PR fix notes

PR #64171: plugins: preserve contextEngine during plugin config normalization

Description (problem / solution / changelog)

Summary

  • preserve plugins.slots.contextEngine in normalized plugin config
  • add a regression test covering the contextEngine slot
  • tighten the warning text to say the effective allowlist is empty

Why

Fixes openclaw/openclaw#64170.

Without this, slot-selected context-engine plugins lose explicit-selection credit after normalization, which can produce a false plugins.allow is empty warning even when the raw config is fine.

Testing

  • pnpm exec vitest run src/plugins/config-policy.test.ts src/plugins/slots.test.ts

Notes

I also tried the repository's full commit-time checks, but they currently fail in unrelated Discord extension types on a fresh checkout:

  • extensions/discord/src/components-registry.ts(2,38): error TS2305 ...
  • plus related DiscordModalEntry / modal type errors

So the focused plugin tests passed, but the full pre-commit check is presently red for unrelated reasons.

Changed files

  • src/plugins/config-normalization-shared.ts (modified, +3/-0)
  • src/plugins/config-policy.test.ts (modified, +14/-0)
  • src/plugins/loader.ts (modified, +1/-1)

PR #64192: fix(plugins): preserve contextEngine slot through config normalization

Description (problem / solution / changelog)

Summary

normalizePluginsConfigWithResolver() in src/plugins/config-normalization-shared.ts reconstructed the slots object with only the memory key, silently dropping contextEngine. This caused slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics.

Fixes #64170

Symptom

{
  "plugins": {
    "allow": ["cortex", "eva-xt", "lossless-claw"],
    "slots": {
      "memory": "cortex",
      "contextEngine": "lossless-claw"
    }
  }
}

After normalization, slots.contextEngine is undefined. Loader diagnostics then treat the discovered context-engine plugin as not explicitly selected, and warnWhenAllowlistIsOpen() emits a false warning:

[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load ...

Root cause

// config-normalization-shared.ts:143-145 (before fix)
slots: {
  memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
  // contextEngine: missing — silently dropped
},

The zod schema (zod-schema.ts:938) accepts contextEngine: z.string().optional(), and the raw config preserves it, but the normalization function discards it during reconstruction.

Fix

Add contextEngine to the normalized slots object using the same normalizeSlotValue helper already used for memory:

 slots: {
   memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
+  contextEngine: normalizeSlotValue(config?.slots?.contextEngine),
 },

And add contextEngine?: string | null to the NormalizedPluginsConfig type.

Unlike memory (which defaults to "memory-core" when absent), contextEngine has no default — it's undefined when not explicitly configured.

Tests

Added 5 parameterized cases in src/plugins/config-state.test.ts:

InputExpected
{} (absent)undefined
{ contextEngine: "lossless-claw" }"lossless-claw"
{ contextEngine: "none" }null
{ contextEngine: " cortex " }"cortex" (trimmed)
{ contextEngine: "" }undefined

Scope

  • Files: src/plugins/config-normalization-shared.ts (+2), src/plugins/config-state.test.ts (+10)
  • Production LOC: 2 lines (1 type field + 1 normalize call)
  • oxlint clean
  • Zero competition: no open PRs touch normalizePluginsConfigWithResolver or the contextEngine slot

Credit to @100yenadmin for the precise call-chain RCA in #64170.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/plugins/config-normalization-shared.ts (modified, +2/-0)
  • src/plugins/config-policy.ts (modified, +18/-1)
  • src/plugins/config-state.test.ts (modified, +50/-0)
  • src/plugins/config-state.ts (modified, +20/-1)

PR #64223: fix(plugins): preserve context engine slot normalization

Description (problem / solution / changelog)

Closes #64170

Summary

  • preserve plugins.slots.contextEngine during plugin config normalization
  • update the open-allowlist warning text to describe the effective allowlist
  • add regression coverage for the normalized context engine slot

Test Plan

  • pnpm --dir /Users/wentao/Desktop/openclaw exec vitest run src/plugins/config-policy.test.ts src/plugins/loader.test.ts src/config/config.plugin-validation.test.ts src/agents/skills/workspace.load-order.test.ts
  • NODE_OPTIONS=--max-old-space-size=8192 pnpm --dir /Users/wentao/Desktop/openclaw exec tsc --noEmit --pretty false

Changed files

  • extensions/comfy/image-generation-provider.test.ts (modified, +26/-0)
  • extensions/comfy/music-generation-provider.test.ts (modified, +67/-0)
  • extensions/comfy/video-generation-provider.test.ts (modified, +28/-0)
  • extensions/comfy/workflow-runtime.ts (modified, +5/-2)
  • extensions/memory-core/src/memory/index.test.ts (modified, +6/-0)
  • extensions/memory-core/src/memory/provider-adapters.ts (modified, +39/-1)
  • extensions/whatsapp/src/session.runtime.ts (modified, +1/-0)
  • extensions/whatsapp/src/session.test.ts (modified, +67/-27)
  • extensions/whatsapp/src/session.ts (modified, +33/-1)
  • src/agents/tools/sessions-announce-target.ts (modified, +15/-1)
  • src/agents/tools/sessions-helpers.ts (modified, +2/-0)
  • src/agents/tools/sessions.test.ts (modified, +27/-0)
  • src/infra/outbound/message-action-params.test.ts (modified, +36/-1)
  • src/infra/outbound/message-action-params.ts (modified, +7/-2)
  • src/memory-host-sdk/engine-embeddings.ts (modified, +4/-0)
  • src/plugins/config-normalization-shared.ts (modified, +3/-0)
  • src/plugins/config-policy.test.ts (modified, +12/-0)
  • src/plugins/loader.test.ts (modified, +3/-1)
  • src/plugins/loader.ts (modified, +1/-1)
  • test/mocks/baileys.ts (modified, +8/-0)

PR #64387: fix(plugins): include activationSourceConfig in loadOpenClawPlugins destructuring

Description (problem / solution / changelog)

Summary

  • resolvePluginLoadCacheContext returns activationSourceConfig in its result object (used to thread the original raw config through to activation-source creation)
  • loadOpenClawPlugins destructures the result but omits activationSourceConfig
  • The compiled build (2026.4.9, loader-BSIqIOsD.js) injects a diagnostic log inside loadOpenClawPlugins that references activationSourceConfig as a bare variable
  • Since the variable was never destructured, this causes ReferenceError: activationSourceConfig is not defined, crash-looping the gateway on every startup attempt

One-line fix

Add activationSourceConfig to the destructuring at loadOpenClawPlugins line ~1092.

Reproduction

  1. Install OpenClaw 2026.4.9 via pnpm/npm
  2. Start the gateway (openclaw gateway start or via LaunchAgent)
  3. Gateway crash-loops: starting...loading configuration…resolving authentication… → crash → repeat every ~4s
  4. ~/.openclaw/logs/gateway.err.log shows: Gateway failed to start: ReferenceError: activationSourceConfig is not defined

Evidence

Gateway error log (repeating every ~4 seconds):

2026-04-10T14:14:03.652+03:00 Gateway failed to start: ReferenceError: activationSourceConfig is not defined
2026-04-10T14:14:07.982+03:00 Gateway failed to start: ReferenceError: activationSourceConfig is not defined
2026-04-10T14:14:12.218+03:00 Gateway failed to start: ReferenceError: activationSourceConfig is not defined

Compiled code trace

In loader-BSIqIOsD.js:

Line ~1996resolvePluginLoadCacheContext declares and returns activationSourceConfig:

const activationSourceConfig = options.activationSourceConfig ?? options.config ?? {};
// ...
return { env, cfg, normalized, activationSourceConfig, activationSource, ... };

Line ~2336loadOpenClawPlugins destructures but omits it:

const { env, cfg, normalized, activationSource, autoEnabledReasons, ... } = resolvePluginLoadCacheContext(options);
//                              ^ missing activationSourceConfig here

Line ~2446 — a diagnostic log references it as a bare variable:

if (shouldActivate) logger.warn(`[plugins-diag] ... activation.plugins=${JSON.stringify(activationSourceConfig?.plugins ?? null)}`);
// ReferenceError: activationSourceConfig is not defined

Environment

  • OpenClaw: 2026.4.9 (0512059)
  • Node.js: v25.9.0
  • OS: macOS 26.3.1 (arm64)

AI-assisted

  • AI-assisted (Claude Code / Opus 4.6)
  • Tested locally: applied equivalent patch to compiled loader-BSIqIOsD.js, confirmed gateway starts successfully
  • I understand what the code does

Related issues

Fixes #64357

Related (same symptom family — false plugins.allow is empty warnings):

  • #62049, #64170, #62521, #63693, #63182

Possibly related (plugin loading crashes/hangs):

  • #64306, #64354

Test plan

  • pnpm build && pnpm check && pnpm test passes
  • Gateway starts without crash-loop on fresh install
  • openclaw doctor no longer shows activationSourceConfig ReferenceError

Changed files

  • scripts/check-no-raw-channel-fetch.mjs (modified, +1/-1)
  • src/plugins/loader.ts (modified, +2/-0)
  • test/scripts/lint-suppressions.test.ts (modified, +1/-0)

Code Example

{
  "plugins": {
    "allow": ["cortex", "eva-xt", "lossless-claw"],
    "slots": {
      "memory": "cortex",
      "contextEngine": "lossless-claw"
    }
  }
}

---

[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load ...

---

const memorySlot = normalizeSlotValue(config?.slots?.memory);
return {
  ...
  slots: {
    memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
  },
  ...
};

---

diff --git a/src/plugins/config-normalization-shared.ts b/src/plugins/config-normalization-shared.ts
@@
 export type NormalizedPluginsConfig = {
@@
   slots: {
     memory?: string | null;
+    contextEngine?: string | null;
   };
@@
 ): NormalizedPluginsConfig {
   const memorySlot = normalizeSlotValue(config?.slots?.memory);
+  const contextEngineSlot = normalizeSlotValue(config?.slots?.contextEngine);
   return {
@@
     slots: {
       memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
+      ...(contextEngineSlot !== undefined ? { contextEngine: contextEngineSlot } : {}),
     },

---

diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts
@@
-  `[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: ...`
+  `[plugins] effective plugin allowlist is empty; discovered non-bundled plugins may auto-load: ...`

---

pnpm exec vitest run src/plugins/config-policy.test.ts src/plugins/slots.test.ts
RAW_BUFFERClick to expand / collapse

Summary

normalizePluginsConfigWithResolver() preserves plugins.slots.memory but silently drops plugins.slots.contextEngine from the normalized plugin config. That causes slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics.

One visible symptom is a false warning from warnWhenAllowlistIsOpen() saying plugins.allow is empty even when the on-disk config has a populated allowlist and the context engine was selected via plugins.slots.contextEngine.

Repro

Given config like:

{
  "plugins": {
    "allow": ["cortex", "eva-xt", "lossless-claw"],
    "slots": {
      "memory": "cortex",
      "contextEngine": "lossless-claw"
    }
  }
}

At runtime:

  1. loadConfig() returns cfg.plugins.slots.contextEngine = "lossless-claw"
  2. normalizePluginsConfig(cfg.plugins) drops that field and returns only slots.memory
  3. loader diagnostics then treat the discovered non-bundled context-engine plugin as not explicitly selected
  4. warnWhenAllowlistIsOpen() can emit:
[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load ...

Evidence / call trace

  • Config load: src/config/config.ts / runtime loadConfig() path
  • Plugin normalization entrypoint: src/plugins/config-state.ts:142
  • Buggy normalizer: src/plugins/config-normalization-shared.ts:133-145
  • Misleading warning: src/plugins/loader.ts:993-1021

Current normalizer only carries slots.memory:

const memorySlot = normalizeSlotValue(config?.slots?.memory);
return {
  ...
  slots: {
    memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
  },
  ...
};

But the schema/docs/tests already support plugins.slots.contextEngine, so this field is schema-valid input that gets lost later.

Blast radius

Non-blocking for many current setups, but still real:

  • false operator/security warnings about an "empty" allowlist
  • slot-selected context-engine plugins are under-credited as explicitly selected
  • any future logic that relies on normalized slots.contextEngine will silently misbehave

Proposed fix

Preserve contextEngine during normalization and slightly tighten the warning text so it describes the effective loader allowlist instead of the raw config.

diff --git a/src/plugins/config-normalization-shared.ts b/src/plugins/config-normalization-shared.ts
@@
 export type NormalizedPluginsConfig = {
@@
   slots: {
     memory?: string | null;
+    contextEngine?: string | null;
   };
@@
 ): NormalizedPluginsConfig {
   const memorySlot = normalizeSlotValue(config?.slots?.memory);
+  const contextEngineSlot = normalizeSlotValue(config?.slots?.contextEngine);
   return {
@@
     slots: {
       memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
+      ...(contextEngineSlot !== undefined ? { contextEngine: contextEngineSlot } : {}),
     },

and

diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts
@@
-  `[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: ...`
+  `[plugins] effective plugin allowlist is empty; discovered non-bundled plugins may auto-load: ...`

Verification

I verified the fix locally against source by adding a regression test in src/plugins/config-policy.test.ts that asserts contextEngine survives normalization, then running:

pnpm exec vitest run src/plugins/config-policy.test.ts src/plugins/slots.test.ts

Both files passed.

extent analysis

TL;DR

Preserve the contextEngine field during plugin config normalization to prevent it from being silently dropped.

Guidance

  • Update the normalizePluginsConfigWithResolver function to include the contextEngine field in the normalized plugin config.
  • Modify the NormalizedPluginsConfig type to include the contextEngine field in the slots object.
  • Adjust the warning text in warnWhenAllowlistIsOpen to describe the effective loader allowlist instead of the raw config.
  • Verify the fix by adding a regression test that checks if the contextEngine field survives normalization.

Example

The proposed fix includes a code snippet that demonstrates how to preserve the contextEngine field during normalization:

diff --git a/src/plugins/config-normalization-shared.ts b/src/plugins/config-normalization-shared.ts
@@
 export type NormalizedPluginsConfig = {
@@
   slots: {
     memory?: string | null;
+    contextEngine?: string | null;
   };
@@
 ): NormalizedPluginsConfig {
   const memorySlot = normalizeSlotValue(config?.slots?.memory);
+  const contextEngineSlot = normalizeSlotValue(config?.slots?.contextEngine);
   return {
@@
     slots: {
       memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot,
+      ...(contextEngineSlot !== undefined ? { contextEngine: contextEngineSlot } : {}),
     },

Notes

The fix assumes that the contextEngine field is a valid input according to the schema/docs/tests. If this is not the case, additional validation may be necessary.

Recommendation

Apply the proposed workaround by preserving the contextEngine field during plugin config normalization and updating the warning text to describe the effective loader allowlist. This will prevent the contextEngine field from being silently dropped and ensure that slot-selected context-engine plugins are properly credited as explicitly selected.

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