-
-
Notifications
You must be signed in to change notification settings - Fork 52.6k
Description
Description
Plugin HTTP routes registered via api.registerHttpRoute() are unreachable in 2026.3.1 because handleControlUiHttpRequest (SPA catch-all) runs before handlePluginRequest in the gateway request chain.
The same plugin + route works correctly on 2026.2.26.
Steps to Reproduce
- Register a plugin HTTP route synchronously in
register():
register(api) {
api.registerHttpRoute({
path: "/my-plugin/inbound",
handler: async (req, res) => {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true }));
}
});
}openclaw plugins list --jsonconfirms:httpHandlers: 1,status: "loaded",diagnostics: []curl -i -X POST http://127.0.0.1:18789/my-plugin/inboundreturns 405 Method Not Allowed (noAllowheader)curl -i http://127.0.0.1:18789/my-plugin/inboundreturns 200 OK with Control UI HTML
Root Cause
In createGatewayHttpServer (gateway-cli), the request handling order is:
1. handleA2uiHttpRequest
2. canvasHost.handleHttpRequest
3. handleControlUiHttpRequest <-- SPA catch-all, matches ALL paths
4. handlePluginRequest <-- never reached for matching paths
handleControlUiHttpRequest serves HTML for any GET request and returns 405 for POST/PUT/etc on any path. Since it runs before plugin routes, plugin HTTP endpoints are effectively shadowed.
Expected Behavior
Plugin HTTP routes should have priority over the Control UI catch-all, matching the 2026.2.26 behavior.
Suggested Fix
Move handlePluginRequest (with its auth check) before handleControlUiHttpRequest in the request chain.
Possible Workaround
Set gateway.controlUi.basePath to a specific prefix (e.g. /ui) so the catch-all doesn't match plugin paths. (Untested)
Environment
- OpenClaw version: 2026.3.1
- OS: Linux (Debian 12, Hetzner VPS)
- Node: v22.22.0
- Working version: 2026.2.26