Skip to content

[2026.3.1 regression] Control UI handler runs before plugin HTTP routes — plugin routes unreachable #31766

@FayAndXan

Description

@FayAndXan

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

  1. 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 }));
    }
  });
}
  1. openclaw plugins list --json confirms: httpHandlers: 1, status: "loaded", diagnostics: []
  2. curl -i -X POST http://127.0.0.1:18789/my-plugin/inbound returns 405 Method Not Allowed (no Allow header)
  3. curl -i http://127.0.0.1:18789/my-plugin/inbound returns 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions