openclaw - ✅(Solved) Fix [Bug]: BlueBubbles webhook route returns 404 despite successful registration [2 pull requests, 7 comments, 6 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#52095Fetched 2026-04-08 01:15:41
View on GitHub
Comments
7
Participants
6
Timeline
19
Reactions
0
Author
Timeline (top)
commented ×7referenced ×3cross-referenced ×2labeled ×2

BlueBubbles webhook endpoint returns 404 Not Found despite logs showing successful route registration at startup.

Root Cause

HTTP request returns 404 because the plugin HTTP route is not being matched by the gateway's request handler. The response is plain text "Not Found", indicating it's caught by the Control UI SPA fallback handler instead of the plugin route handler.

Fix Action

Fix / Workaround

Workaround: None currently available. Inbound iMessage messages cannot be received via BlueBubbles webhook.

PR fix notes

PR #52764: fix(plugins): resolve BlueBubbles webhook 404 when pinned registry empty (#52095)

Description (problem / solution / changelog)

Summary

  • Problem: BlueBubbles webhook requests to /bluebubbles-webhook return 404 even when the BlueBubbles plugin is loaded and registers HTTP routes. The handler uses the pinned registry, which can be empty while routes exist in state.registry (e.g., after pin or during plugin reload).
  • Why it matters: Users cannot receive iMessage events; the BlueBubbles integration fails silently.
  • What changed: Added a fallback in resolveActivePluginHttpRouteRegistry: when the pinned registry has no HTTP routes but state.registry does, use state.registry. Updated plugins-http handler to call resolveActivePluginHttpRouteRegistry to resolve the registry before lookup.
  • What did NOT change: No config changes, no API changes, no behavior change for normal cases where the pinned registry already has routes.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Integrations

Linked Issue/PR

  • Closes #52095

User-visible / Behavior Changes

None. BlueBubbles webhook works when it previously returned 404.

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

Repro + Verification

Environment

  • OS: Windows / macOS
  • Runtime/container: Node
  • Integration/channel: BlueBubbles (iMessage)
  • Relevant config: channels.bluebubbles enabled, webhook path /bluebubbles-webhook

Steps

  1. Configure BlueBubbles channel and start gateway.
  2. From Mac (BlueBubbles server), send a webhook POST to http://gateway:18789/bluebubbles-webhook?password=<pwd>.
  3. Previously: 404. After fix: 200, handler processes the event.

Expected

  • 200 OK, webhook handled.

Actual (before fix)

  • 404 Not Found.

Evidence

  • Regression test added: runtime.test.ts — "falls back to state.registry when pinned is empty but state.registry has routes (issue #52095)"

Human Verification (required)

  • Verified scenarios: BlueBubbles webhook receives events and processes them after fix; pnpm test passes.
  • Edge cases checked: Pinned registry empty + state.registry has routes.
  • What you did not verify: Other plugin HTTP routes (unchanged code path when pinned registry has routes).

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

Failure Recovery (if this breaks)

  • Revert the 3 files: src/plugins/runtime.ts, src/plugins/runtime.test.ts, src/gateway/server/plugins-http.ts.
  • Known bad symptoms: BlueBubbles webhook returning 404 again.

Risks and Mitigations

None.

Changed files

  • docs/personal-ai-assistant-plan.md (added, +298/-0)
  • src/gateway/server/plugins-http.ts (modified, +3/-0)
  • src/plugins/runtime.test.ts (modified, +20/-0)
  • src/plugins/runtime.ts (modified, +9/-0)

PR #54686: Fix for hooks and bluebubbles webhook 404 (closes #52605 and others)

Description (problem / solution / changelog)

Summary

-Problem: Plugin HTTP routes (e.g. /bluebubbles-webhook, /line/webhook) return 404 even though plugins log successful registration; gateway sees an empty or stale plugin registry (PLUGINS: []). -Why it matters: Breaks all inbound webhooks (BlueBubbles, LINE, etc.), making channels unusable while appearing healthy. -What changed: Added syncPluginRegistry() and invoked it at runtime boundaries (request handling + channel lifecycle) to ensure the active plugin registry is always aligned with the runtime state. -What did NOT change (scope boundary): No changes to route matching, plugin registration logic, hooks behavior, or HTTP handler ordering.

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 #53927 Closes #52605 Closes #52095 Related #52729 There may be more related/closed but I would still have to look through, as keywords 'webhook 404'bring up 46 open issues

  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

-Root cause: The HTTP server and request handler operate on a different or stale plugin registry instance than the one mutated during plugin initialization, resulting in no visible plugin routes at request time.

-Missing detection / guardrail: No runtime assertion or validation that the active plugin registry used by HTTP handling matches the registry populated by plugins.

-Prior context: Multiple reports in v2026.3.x of webhook routes logging as registered but returning 404; suspected registry mismatch or initialization ordering issues.

-Why this regressed now: Likely introduced by changes in plugin runtime state handling or registry lifecycle in v2026.3.x, causing divergence between global runtime state and active registry.

-If unknown, what was ruled out: Route path mismatch, Control UI SPA interception, and handler ordering were ruled out (404 occurs even on correct paths and before SPA fallback).

Regression Test Plan (if applicable)

-Target test or file: Gateway HTTP integration test covering plugin route registration + POST handling

-Scenario the test should lock in: Register plugin HTTP route → send POST → expect non-404 (e.g. 200/400), not "Not Found"

-Why this is the smallest reliable guardrail: Requires both plugin init and HTTP handler using the same registry instance

-Existing test that already covers this: None reliably catching registry desync

-If no new test is added, why not: Out of scope for this PR; focused on minimal runtime fix

User-visible / Behavior Changes

Webhook endpoints (e.g. /bluebubbles-webhook, /line/webhook) now correctly resolve instead of returning 404 when plugins are active.

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)

Repro + Verification

Environment

OS: Linux (local dev) Runtime/container: Node.js Model/provider: N/A Integration/channel: BlueBubbles, LINE Relevant config: channels configured with webhook paths

Steps

  1. Start gateway with BlueBubbles or LINE configured
  2. Observe logs: webhook “listening” message
  3. Send POST to webhook endpoint

Expected

Non-404 response (e.g. 200 or 400 depending on payload/auth)

Actual

Before fix: 404 Not Found After fix: route handled correctly

Attach at least one:

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

example: PLUGINS: [] POST /bluebubbles-webhook results in 404

after: PLUGINS: [bluebubbles, ...] POST /bluebubbles-webhook is handled

Human Verification (required)

What you personally verified (not just CI), and how:

-Verified scenarios: BlueBubbles webhook responds after fix Plugin list no longer empty during request handling

-Edge cases checked: Repeated requests Gateway restart

-What you did not verify: All channel plugins hooks.internal.enabled interactions exhaustively

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)

Failure Recovery (if this breaks)

-How to disable/revert this change quickly: Revert syncPluginRegistry calls

-Files/config to restore: server-channels.ts gateway-http.ts

-Known bad symptoms reviewers should watch for: Plugin routes disappearing again Duplicate registry state issues

Risks and Mitigations

-Risk: Repeated registry syncing could mask deeper lifecycle bugs -Mitigation: Minimal, idempotent sync; does not mutate registry, only aligns reference

-Risk: Global state dependency (globalThis) could introduce hidden coupling -Mitigation: Read-only access pattern; no mutation of runtime state

Changed files

  • src/gateway/server-channels.ts (modified, +26/-0)
  • src/gateway/server-http.ts (modified, +8/-4)
  • src/plugins/runtime.ts (modified, +18/-1)

Code Example

curl -X POST "http://localhost:18789/bluebubbles-webhook?password=xxx" \
     -H "Content-Type: application/json" \
     -d '{"type":"new-message","data":{"text":"test"}}'

---

Gateway logs:

{"subsystem":"gateway/channels/bluebubbles","message":"[default] starting provider (webhook=/bluebubbles-webhook)"}
{"subsystem":"gateway/channels/bluebubbles","message":"[default] BlueBubbles webhook listening on /bluebubbles-webhook"}


HTTP test:

$ curl -v -X POST "http://192.168.100.11:18789/bluebubbles-webhook?password=xxx"
> POST /bluebubbles-webhook?password=xxx HTTP/1.1
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< 
Not Found
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

BlueBubbles webhook endpoint returns 404 Not Found despite logs showing successful route registration at startup.

Steps to reproduce

  1. Configure BlueBubbles channel with webhookPath: "/bluebubbles-webhook"
  2. Start OpenClaw gateway
  3. Observe logs: BlueBubbles webhook listening on /bluebubbles-webhook
  4. Test webhook endpoint:
    curl -X POST "http://localhost:18789/bluebubbles-webhook?password=xxx" \
      -H "Content-Type: application/json" \
      -d '{"type":"new-message","data":{"text":"test"}}'
  5. Result: Returns 404 Not Found (plain text response from SPA fallback)

Expected behavior

The webhook endpoint should receive and process the request, returning a proper response from the BlueBubbles plugin handler.

Actual behavior

HTTP request returns 404 because the plugin HTTP route is not being matched by the gateway's request handler. The response is plain text "Not Found", indicating it's caught by the Control UI SPA fallback handler instead of the plugin route handler.

OpenClaw version

2026.3.13 (61d171a)

Operating system

macOS 13.7.8

Install method

npm global

Model

api-ai-yuanjing-chinaunicom/glm-5

Provider / routing chain

openclaw -> api-ai-yuanjing-chinaunicom (direct provider)

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Gateway logs:

{"subsystem":"gateway/channels/bluebubbles","message":"[default] starting provider (webhook=/bluebubbles-webhook)"}
{"subsystem":"gateway/channels/bluebubbles","message":"[default] BlueBubbles webhook listening on /bluebubbles-webhook"}


HTTP test:

$ curl -v -X POST "http://192.168.100.11:18789/bluebubbles-webhook?password=xxx"
> POST /bluebubbles-webhook?password=xxx HTTP/1.1
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< 
Not Found

Impact and severity

Affected: All BlueBubbles channel users Severity: High (blocks all inbound iMessage functionality) Frequency: 100% (always) Consequence: No inbound iMessage messages can be received; BlueBubbles channel is completely non-functional for incoming messages

Additional information

Root cause analysis: After code analysis, the issue appears to be in the plugin HTTP route registration mechanism:

  1. registerPluginHttpRoute() registers routes to requireActivePluginRegistry().httpRoutes
  2. Plugin initializes and calls registerWebhookTargetWithPluginRoute() which uses registerPluginHttpRoute()
  3. Routes are successfully added to the global registry state
  4. However, the HTTP request handler uses handlePluginRequest which is created with params.pluginRegistry
  5. There may be a mismatch between the registry instance used during plugin initialization and the one passed to the HTTP server

Workaround: None currently available. Inbound iMessage messages cannot be received via BlueBubbles webhook.

extent analysis

Fix Plan

To resolve the issue, we need to ensure that the handlePluginRequest function uses the same pluginRegistry instance as the one used during plugin initialization.

Here are the steps to fix the issue:

  • Update the handlePluginRequest function to use the global requireActivePluginRegistry() instead of params.pluginRegistry.
  • Verify that the registerPluginHttpRoute() function is correctly registering the routes to the global registry state.

Example code changes:

// Before
const handlePluginRequest = (req, res) => {
  const pluginRegistry = params.pluginRegistry;
  // ...
};

// After
const handlePluginRequest = (req, res) => {
  const pluginRegistry = requireActivePluginRegistry();
  // ...
};

Additionally, we should verify that the registerPluginHttpRoute() function is correctly registering the routes:

// Verify route registration
const registerPluginHttpRoute = (route) => {
  const registry = requireActivePluginRegistry();
  registry.httpRoutes.push(route);
  // ...
};

Verification

To verify that the fix worked, we can test the webhook endpoint again using the curl command:

curl -X POST "http://localhost:18789/bluebubbles-webhook?password=xxx" \
  -H "Content-Type: application/json" \
  -d '{"type":"new-message","data":{"text":"test"}}'

If the fix is successful, the endpoint should return a proper response from the BlueBubbles plugin handler instead of a 404 error.

Extra Tips

To prevent similar issues in the future, it's essential to ensure that all components are using the same instance of the pluginRegistry. We can achieve this by using a singleton pattern or a dependency injection mechanism to provide the pluginRegistry instance to all components that need it.

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

The webhook endpoint should receive and process the request, returning a proper response from the BlueBubbles plugin handler.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: BlueBubbles webhook route returns 404 despite successful registration [2 pull requests, 7 comments, 6 participants]