-
-
Notifications
You must be signed in to change notification settings - Fork 52.6k
Description
Description
After upgrading to 2026.3.1, all BlueBubbles webhook POST requests return 405 Method Not Allowed. The gateway starts fine and reports BlueBubbles as OK in openclaw status --deep, but incoming iMessages are never delivered because the webhook handler never receives them.
Root Cause
handleControlUiHttpRequest in gateway-cli-tzSO700C.js (line ~16917) rejects all non-GET/HEAD requests with 405 before checking the URL path:
function handleControlUiHttpRequest(req, res, opts) {
const urlRaw = req.url;
if (!urlRaw) return false;
if (req.method !== "GET" && req.method !== "HEAD") {
res.statusCode = 405;
res.end("Method Not Allowed");
return true; // <-- claims it handled the request
}
// ...basePath matching happens AFTER, never reached for POST
}Since 2026.3.1 changed handler ordering to "run plugin handlers after built-in handlers for deterministic route precedence" (Gateway/Plugin HTTP auth hardening), the controlUi handler now runs before plugin webhook routes. Every POST to any path gets caught and 405'd before the BB webhook plugin handler can process it.
Reproduction
- Fresh install or upgrade to 2026.3.1
- Configure BlueBubbles channel (working config, BB server healthy)
- Send an iMessage — never delivered
- Confirm with curl:
curl -X POST http://127.0.0.1:18789/bluebubbles-webhook?password=xxx -H 'Content-Type: application/json' -d '{}' # Returns: 405 Method Not Allowed
Workaround
Disable controlUi in config:
{
"gateway": {
"controlUi": {
"enabled": false
}
}
}Then openclaw gateway restart. Webhooks return 200 again. Downside: dashboard is inaccessible.
Suggested Fix
Move the method check after the basePath match so non-matching paths return false and fall through to plugin handlers:
function handleControlUiHttpRequest(req, res, opts) {
const urlRaw = req.url;
if (!urlRaw) return false;
const url = new URL(urlRaw, "http://localhost");
const basePath = normalizeControlUiBasePath(opts?.basePath);
// Check path first — if this isn't a controlUi route, don't handle it
if (basePath && url.pathname !== basePath && !url.pathname.startsWith(basePath + "/")) {
return false;
}
// Now safe to enforce method
if (req.method !== "GET" && req.method !== "HEAD") {
res.statusCode = 405;
res.end("Method Not Allowed");
return true;
}
// ...rest of handler
}Environment
- OpenClaw: 2026.3.1
- macOS: 26.3.0 (arm64)
- Node: 25.5.0
- BlueBubbles Server: 1.9.9
- Gateway bind: loopback, port 18789
Affected Channels
This likely affects all webhook-based channels (BlueBubbles, Telegram webhook mode, Google Chat webhook, etc.), not just BlueBubbles.