openclaw - ✅(Solved) Fix [Bug]: Plugin loader can overwrite gateway-bindable hook runner during later default plugin loads [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#63166Fetched 2026-04-09 07:57:35
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
labeled ×2cross-referenced ×1

When the gateway starts with a gateway-bindable plugin registry, later default-mode activating plugin loads can overwrite the process-global hook runner.

This is a problem for plugins that depend on the gateway-startup hook surface staying stable across the lifetime of the process.

Root Cause

Some plugin runtime paths still resolve runtime registries dynamically and may trigger a fresh activating load on cache miss.

If that happens after gateway startup, the active gateway hook surface can silently drift away from the original gateway-bindable registry.

This can break plugins that rely on gateway-installed hooks such as:

  • before_agent_reply
  • subagent_delivery_target
  • subagent_ended

Fix Action

Fixed

PR fix notes

PR #63168: plugins: preserve gateway-bindable hook runner

Description (problem / solution / changelog)

Summary

  • preserve the existing global hook runner when a later default-mode activating load happens after a gateway-bindable load
  • add a regression test that proves the gateway-bindable hook runner is not overwritten
  • keep the change minimal and scoped to the loader activation path

Test plan

  • pnpm test src/plugins/loader.test.ts -t "preserves the gateway-bindable hook runner across later default activating loads"

Relevant issue

[Bug]: Plugin loader can overwrite gateway-bindable hook runner during later default plugin loads

Changed files

  • src/gateway/server-plugin-bootstrap.ts (modified, +14/-3)
  • src/gateway/server-plugins.test.ts (modified, +41/-0)
  • src/gateway/server-runtime-state.ts (modified, +4/-1)
  • src/plugins/hook-runner-global.ts (modified, +3/-0)
  • src/plugins/loader.test.ts (modified, +123/-1)
  • src/plugins/loader.ts (modified, +6/-1)
  • src/plugins/runtime-state.ts (modified, +6/-0)
  • src/plugins/runtime.hook-pin.test.ts (added, +111/-0)
  • src/plugins/runtime.ts (modified, +42/-0)
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

Yes

Summary

Summary

When the gateway starts with a gateway-bindable plugin registry, later default-mode activating plugin loads can overwrite the process-global hook runner.

This is a problem for plugins that depend on the gateway-startup hook surface staying stable across the lifetime of the process.

What happens

loadOpenClawPlugins() always reinitializes the global hook runner during activation.

That means a later default-mode activating load can replace the hook runner that was originally initialized from the gateway-bindable registry.

Why this matters

Some plugin runtime paths still resolve runtime registries dynamically and may trigger a fresh activating load on cache miss.

If that happens after gateway startup, the active gateway hook surface can silently drift away from the original gateway-bindable registry.

This can break plugins that rely on gateway-installed hooks such as:

  • before_agent_reply
  • subagent_delivery_target
  • subagent_ended

Expected behavior

Once gateway startup installs a gateway-bindable hook runner, later default-mode activating loads should not replace it.

Reproduction idea

  1. Start with a plugin load using runtimeOptions.allowGatewaySubagentBinding = true.
  2. Confirm the global hook runner points at that registry.
  3. Trigger a later default activating plugin load with a different plugin set.
  4. Observe that the global hook runner gets replaced.

Proposed fix

Preserve the existing global hook runner when:

  • the previously active runtime subagent mode is gateway-bindable
  • the new activating load is default

Notes

This is similar to how other plugin runtime surfaces already need protection from later non-primary loads. The hook runner currently behaves like an unpinned global mutable surface.

Steps to reproduce

see summary abrove

Expected behavior

see summary abrove

Actual behavior

see summary abrove

OpenClaw version

2026.4.8

Operating system

macOS 14.7.8 (23H730)

Install method

pnpm dev

Model

mimo-v2-pro

Provider / routing chain

locally

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

Preserve the existing global hook runner when the previously active runtime subagent mode is gateway-bindable and the new activating load is default.

Guidance

  • Identify the loadOpenClawPlugins() function and modify it to check the current runtime subagent mode before reinitializing the global hook runner.
  • Add a conditional statement to preserve the existing global hook runner if the previous mode is gateway-bindable and the new load is default.
  • Verify the fix by reproducing the issue with the modified code and checking that the global hook runner remains unchanged after a later default-mode activating load.
  • Review other plugin runtime surfaces to ensure they are also protected from later non-primary loads.

Example

if (previousMode === 'gateway-bindable' && newLoadMode === 'default') {
  // Preserve the existing global hook runner
  // ...
} else {
  // Reinitialize the global hook runner
  loadOpenClawPlugins();
}

Notes

The proposed fix assumes that the loadOpenClawPlugins() function is the only entry point for reinitializing the global hook runner. Additional checks may be necessary to ensure that other parts of the code do not modify the hook runner unexpectedly.

Recommendation

Apply the proposed workaround to preserve the existing global hook runner, as it addresses the specific issue described and prevents the hook runner from being silently replaced.

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…

FAQ

Expected behavior

see summary abrove

Still need to ship something?

×6

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

Back to top recommendations

TRENDING