openclaw - ✅(Solved) Fix [Bug] Plugin services (recall_manager, openviking) fail to register with 'service already registered' after upgrading to 2026.4.5 [1 pull requests, 1 comments, 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#62033Fetched 2026-04-08 03:10:02
View on GitHub
Comments
1
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
commented ×1

After upgrading to OpenClaw 2026.4.5 (2026-04-05), Gateway startup fails with repeated "service already registered" errors for custom plugins (recall_manager and openviking). The plugins enter an infinite registration loop.

Error Message

Error Messages

Root Cause

Root Cause Analysis

Fix Action

Workaround

Remove the problematic plugins from plugins.allow list entirely (not just disable via enabled: false).

PR fix notes

PR #64128: [Bug] Plugin services (recall_manager, openviking) fail to register with 'service already registered' after upgrading to 2026.4.5

Description (problem / solution / changelog)

Summary

  • Problem: plugin registry assembly could emit a false-positive service already registered diagnostic when the same plugin id re-registered the same service id during snapshot/repeated activation-style loads.
  • Why it matters: snapshot and activation passes should be idempotent for a plugin's own service registration; the old behavior produced noisy diagnostics that looked like a real duplicate-owner conflict.
  • What changed: src/plugins/registry.ts now treats same-plugin duplicate registerService() calls as idempotent while still rejecting cross-plugin collisions. src/plugins/loader.test.ts adds a regression test for the same-plugin replay case, and CHANGELOG.md records the fix.
  • What did NOT change (scope boundary): cross-plugin duplicate service ids still surface an error, and no plugin loading contract outside this narrow service-registration branch changed.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #62033
  • Related #64128
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: registerService() only keyed on service id and treated any second registration as a duplicate, even when the existing owner was the same plugin being replayed.
  • Missing detection / guardrail: there was coverage for cross-plugin duplicate service ids, but not for same-plugin duplicate registration during replay/snapshot-style assembly.
  • Contributing context (if known): snapshot/non-activating loads can assemble the same plugin registry path more than once.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/plugins/loader.test.ts
  • Scenario the test should lock in: the same plugin registers the same service id twice and keeps a single service registration without emitting service already registered.
  • Why this is the smallest reliable guardrail: it exercises the real plugin loader/registry path that produced the false positive without needing a full gateway run.
  • Existing test that already covers this (if any): existing coverage only locked in the cross-plugin duplicate rejection path.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Snapshot and activation-style plugin loads no longer emit a spurious service already registered diagnostic when the duplicate registration belongs to the same plugin.

Diagram (if applicable)

Before:
[same plugin load pass 1] -> registerService(shared-service)
[same plugin load pass 2] -> duplicate-owner error diagnostic

After:
[same plugin load pass 1] -> registerService(shared-service)
[same plugin load pass 2] -> idempotent no-op -> no false-positive diagnostic

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Windows 10
  • Runtime/container: Node 22+ repo scripts
  • Model/provider: N/A
  • Integration/channel (if any): plugin loader / registry
  • Relevant config (redacted): test plugin allowed through plugins.entries.*.allow

Steps

  1. Load a plugin whose register(api) calls api.registerService({ id: shared-service, ... }) twice.
  2. Inspect registry.services and registry.diagnostics.
  3. Compare that with the existing cross-plugin duplicate-service scenario.

Expected

  • Same-plugin duplicate registration is a no-op.
  • Cross-plugin duplicate registration still raises service already registered.

Actual

  • Before this fix, the same-plugin replay path also emitted the duplicate-service error.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: rebased onto current main, reviewed the final diff to confirm the same-plugin idempotent guard stays narrow, and added loader coverage for the exact replay case Greptile flagged.
  • Edge cases checked: cross-plugin duplicate service rejection remains unchanged; same-plugin duplicate registration still leaves a single registry.services entry.
  • What you did not verify: I could not complete a local pnpm test src/plugins/loader.test.ts run on this Windows machine because the repo test entrypoint fails before collecting tests with an existing Vitest runner initialization error in test/non-isolated-runner.ts (Class extends value undefined is not a constructor or null). I also ran pnpm build because this touches plugin registry/loader code; that failed in this workspace on pre-existing unrelated unresolved-import warnings across optional extension dependencies before reaching a clean build result.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: making duplicate registration idempotent too broadly could hide a real ownership conflict.
    • Mitigation: the guard only returns early when both the service id and owning pluginId already match; cross-plugin collisions still error and are covered by existing tests.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/plugins/loader.test.ts (modified, +29/-1)
  • src/plugins/registry.ts (modified, +5/-0)

Code Example

[plugins] recall_manager failed during register: service already registered: recall_manager (recall_manager)
[plugins] openviking failed during register: service already registered: openviking (openviking)

---

"plugins": {
     "allow": ["recall_manager", "openviking", ...],
     "entries": {
       "recall_manager": { "enabled": true },
       "openviking": { "enabled": true }
     }
   }

---

"plugins": {
  "allow": ["telegram", "slack", "discord", "tavily", "minimax", "zai", "moonshot"],
  "entries": {
    "recall_manager": { "enabled": false },
    "openviking": { "enabled": false }
  }
}
RAW_BUFFERClick to expand / collapse

Summary

After upgrading to OpenClaw 2026.4.5 (2026-04-05), Gateway startup fails with repeated "service already registered" errors for custom plugins (recall_manager and openviking). The plugins enter an infinite registration loop.

Environment

  • OpenClaw version: 2026.4.5 (upgraded from 2026.4.2)
  • Plugin 1: recall_manager (Recall.ai meeting bot dispatcher) - custom plugin
  • Plugin 2: openviking (Context Engine memory plugin) - custom plugin
  • Node: v22.x
  • OS: Linux

Error Messages

[plugins] recall_manager failed during register: service already registered: recall_manager (recall_manager)
[plugins] openviking failed during register: service already registered: openviking (openviking)

These errors repeat continuously during gateway startup, indicating an infinite registration loop.

Repro

  1. Install two custom plugins:

    • recall_manager - registers a service with id: "recall_manager"
    • openviking - registers a service with id: "openviking"
  2. Configure in openclaw.json:

    "plugins": {
      "allow": ["recall_manager", "openviking", ...],
      "entries": {
        "recall_manager": { "enabled": true },
        "openviking": { "enabled": true }
      }
    }
  3. Restart gateway after upgrading to 2026.4.5

Expected

Gateway should start successfully and register both plugins without errors.

Actual

Gateway fails to start - plugins enter infinite registration loop with "service already registered" errors.

Additional Finding

IMPORTANT: The same issue occurs in 2026.4.2 when the plugin is in the allow list, but with less severe consequences:

  • Plugins are re-registered on every agent message
  • This causes unbounded memory growth over time
  • But gateway does not crash (unlike 2026.4.5)

Workaround that works (2026.4.2 and 2026.4.5): Remove the plugin from plugins.allow list entirely:

"plugins": {
  "allow": ["telegram", "slack", "discord", "tavily", "minimax", "zai", "moonshot"],
  "entries": {
    "recall_manager": { "enabled": false },
    "openviking": { "enabled": false }
  }
}

Even with enabled: false in entries, if the plugin is in the allow list, it will still be loaded and re-registered repeatedly.

Root Cause Analysis

Issue #60219 Already Described This

Issue #60219 described an identical problem with the OpenViking plugin. The root cause is:

  1. Gateway calls loadOpenClawPlugins multiple times with different cacheKey values
  2. First call: prefer-setup mode
  3. Second call: full mode
  4. Different cacheKey → cache miss → plugin loaded again
  5. Module-level pluginRegistrationState is not reset between loads with different cacheKeys
  6. This causes duplicate registration attempts that fail silently or cause errors

CHANGELOG Reference (2026.4.5):

Line 710: "Plugins/runtime: reuse only compatible active plugin registries across tools, providers, web search, and channel bootstrap..."

Line 219: "Gateway/channels: pin the initial startup channel registry before later plugin-registry churn..."

The 2026.4.5 changes may have exacerbated this underlying issue.

Potential Fix

  1. Pass consistent preferSetupRuntimeForChannelPlugins to both loadGatewayStartupPlugins and reloadDeferredGatewayPlugins
  2. Reset pluginRegistrationState when loading with a different cacheKey
  3. Use cacheKey-aware state management instead of module-level variables
  4. Consider deduplicating plugin registrations by ID across all registry loads

Workaround

Remove the problematic plugins from plugins.allow list entirely (not just disable via enabled: false).

extent analysis

TL;DR

Remove the custom plugins (recall_manager and openviking) from the plugins.allow list in openclaw.json to prevent the infinite registration loop.

Guidance

  • Verify that the plugins are not essential for the current gateway functionality before removing them from the allow list.
  • Consider disabling the plugins via enabled: false in the entries section of openclaw.json as an alternative, but be aware that this may not prevent the registration loop.
  • Review the CHANGELOG reference for 2026.4.5 to understand the potential impact of the changes on plugin registration.
  • If the issue persists, investigate implementing a cacheKey-aware state management system to deduplicate plugin registrations.

Example

"plugins": {
  "allow": ["telegram", "slack", "discord", "tavily", "minimax", "zai", "moonshot"],
  "entries": {
    "recall_manager": { "enabled": false },
    "openviking": { "enabled": false }
  }
}

Notes

The provided workaround may not be a permanent solution, as it involves removing the plugins from the allow list. A more robust fix would require addressing the underlying issue with plugin registration and cacheKey management.

Recommendation

Apply the workaround by removing the problematic plugins from the plugins.allow list, as it is a proven solution that can prevent the infinite registration loop and allow the gateway to start successfully.

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