Bug type
Behavior bug — silent failure during plugin load.
Beta release blocker
No
Summary
The plugin loader silently drops register* calls that fail acceptance gates. The plugin still loads, the surface never fires, and the only signal is a level=warn diagnostic in gateway.log. Plugins ship green tests against helper-mock APIs and broken in production.
Steps to reproduce
In a plugin, register a hook without opts.name:
api.registerHook(
["before_tool_call", "after_tool_call"],
(event, payload) => { /* ... */ }
);
// Missing: { name: "<plugin>-<purpose>", description: "..." }
Or call api.registerMemoryCapability(...) from a plugin whose manifest does not declare kind: "memory".
The api.registerX(...) call returns successfully. Helper-mock tests pass. The gateway loader logs:
[gateway] [plugins] hook registration missing name (plugin=<id>, source=...)
[gateway] [plugins] only memory plugins can register a memory capability (plugin=<id>, source=...)
…and silently drops the registration. The plugin loads with Status: loaded and the user has no in-band signal that anything is wrong.
Expected behavior
The loader should treat acceptance-gate failures as errors that either:
- Hard-fail the plugin load —
Status: error with the diagnostic surfaced via openclaw plugins doctor, or
- Throw synchronously from the
api.registerX(...) call so the plugin's own error path runs (so unit tests can catch it via expect(...).toThrow)
Either is fine; the current "silent drop, log warn, plugin still loads" is the worst of both worlds — the plugin author has no defect signal until production. Helper-mock unit tests against a fake api cannot catch these gates because the mock has no gate logic.
Actual behavior
Plugin loads successfully. Surface never wires up. The only signal is a level=warn diagnostic in gateway.log that nothing in CI inspects.
Why this matters
Two real cases I hit while developing a plugin:
- A
before_tool_call/after_tool_call telemetry hook registered without opts.name. Helper test passed. Gateway dropped the hook. Telemetry was disabled in production for weeks before I noticed (caught while debugging an unrelated dashboard issue).
registerMemoryCapability(...) registered without declaring kind: "memory" in the manifest. Helper test passed. Gateway rejected the registration at every load. Memory artifacts were never indexed.
Both fixes are trivial once you know about them. The cost is the time-to-detect — which is open-ended without a hard-fail surface.
Proposed fix shape
In loader-*.js registerHook and the gated memory-* registrations, replace pushDiagnostic({ level: "warn"|"error", ... }) + early return with one of:
- A throw from
api.registerX(...) itself (preserves backwards-compat for plugins that already pass valid args; fails loud for plugins that don't)
- A plugin-status downgrade (
Status: error_partial or similar) that openclaw plugins inspect surfaces and CI can grep for
Workaround in use today
A doctor-check that scans gateway.log + gateway.err.log since the most recent gateway] ready event, counts plugin=<id> warnings, and fails CI if non-zero. Works but is per-plugin; an upstream fix would benefit every plugin author.
OpenClaw version
2026.4.24 (cbcfdf6). Source verified against installed /opt/homebrew/lib/node_modules/openclaw/dist/loader-NucjcOgv.js.
Bug type
Behavior bug — silent failure during plugin load.
Beta release blocker
No
Summary
The plugin loader silently drops
register*calls that fail acceptance gates. The plugin still loads, the surface never fires, and the only signal is alevel=warndiagnostic ingateway.log. Plugins ship green tests against helper-mock APIs and broken in production.Steps to reproduce
In a plugin, register a hook without
opts.name:Or call
api.registerMemoryCapability(...)from a plugin whose manifest does not declarekind: "memory".The
api.registerX(...)call returns successfully. Helper-mock tests pass. The gateway loader logs:…and silently drops the registration. The plugin loads with
Status: loadedand the user has no in-band signal that anything is wrong.Expected behavior
The loader should treat acceptance-gate failures as errors that either:
Status: errorwith the diagnostic surfaced viaopenclaw plugins doctor, orapi.registerX(...)call so the plugin's own error path runs (so unit tests can catch it viaexpect(...).toThrow)Either is fine; the current "silent drop, log warn, plugin still loads" is the worst of both worlds — the plugin author has no defect signal until production. Helper-mock unit tests against a fake
apicannot catch these gates because the mock has no gate logic.Actual behavior
Plugin loads successfully. Surface never wires up. The only signal is a
level=warndiagnostic ingateway.logthat nothing in CI inspects.Why this matters
Two real cases I hit while developing a plugin:
before_tool_call/after_tool_calltelemetry hook registered withoutopts.name. Helper test passed. Gateway dropped the hook. Telemetry was disabled in production for weeks before I noticed (caught while debugging an unrelated dashboard issue).registerMemoryCapability(...)registered without declaringkind: "memory"in the manifest. Helper test passed. Gateway rejected the registration at every load. Memory artifacts were never indexed.Both fixes are trivial once you know about them. The cost is the time-to-detect — which is open-ended without a hard-fail surface.
Proposed fix shape
In
loader-*.jsregisterHookand the gated memory-* registrations, replacepushDiagnostic({ level: "warn"|"error", ... })+ earlyreturnwith one of:api.registerX(...)itself (preserves backwards-compat for plugins that already pass valid args; fails loud for plugins that don't)Status: error_partialor similar) thatopenclaw plugins inspectsurfaces and CI can grep forWorkaround in use today
A doctor-check that scans
gateway.log+gateway.err.logsince the most recentgateway] readyevent, countsplugin=<id>warnings, and fails CI if non-zero. Works but is per-plugin; an upstream fix would benefit every plugin author.OpenClaw version
2026.4.24(cbcfdf6). Source verified against installed/opt/homebrew/lib/node_modules/openclaw/dist/loader-NucjcOgv.js.