Skip to content

bug: xRPC-based stream_routes fail check_schema in HTTP worker since 3.16 (regression from #12996) #13325

@horsley

Description

@horsley

Current Behavior

Since APISIX 3.16.0, any stream_route that uses an xRPC protocol (e.g. protocol.name: redis, dubbo, or a custom protocol) emits the following error on every worker startup / config reload in the HTTP subsystem:

[error] *N [lua] config_yaml.lua:333: failed to check item data of [stream_routes] err:unknown protocol [<name>] ,val: {...}, context: init_worker_by_lua*

The same stream_routes entry is accepted by the Stream subsystem (where xrpc.check_schema succeeds), so the tunnel still functions at runtime — but the HTTP worker's view of /stream_routes silently drops the route, and any logic that relies on the HTTP side (for example the Control API healthcheck endpoint added in #12996, or user tests that assert no [error] in error.log) is broken.

Root Cause

#12996 ("feat: allow fetching stream healthcheck data through control api", commit 2500db7a, merged 2026-02-13) changed apisix/router.lua::http_init_worker so that, whenever apisix.stream_proxy is configured, the HTTP worker also initializes the stream router:

https://github.com/apache/apisix/blob/3.16.0/apisix/router.lua#L90-L96

    -- Initialize stream router in HTTP workers only if stream mode is enabled
    -- This allows the Control API (which runs in HTTP workers) to access stream routes
    if conf and conf.apisix and conf.apisix.stream_proxy then
        local router_stream = require("apisix.stream.router.ip_port")
        router_stream.stream_init_worker(filter)
        _M.router_stream = router_stream
    end

stream_init_worker registers a checker that calls xrpc.check_schema(prot_conf, false) for every stream_routes item:

https://github.com/apache/apisix/blob/3.16.0/apisix/stream/router/ip_port.lua#L216-L224

But apisix/stream/xrpc.lua::init still uses the pre-3.16 guard that only registers xRPC protocol schemas in HTTP workers when the Admin API is enabled:

https://github.com/apache/apisix/blob/3.16.0/apisix/stream/xrpc.lua#L59-L62

    if is_http and not local_conf.apisix.enable_admin then
        -- we need to register xRPC protocols in HTTP only when Admin API is enabled
        return
    end

So when a deployment runs with enable_admin: false (e.g. the data-plane role, or any YAML/JSON config_provider), the HTTP worker has registered_protocol_schemas = {} and every xRPC-based stream route fails check_schema"unknown protocol [<name>]".

Expected Behavior

When APISIX 3.16+ initializes the stream router inside the HTTP worker, it should also make sure the xRPC protocol schemas are available, so that check_schema succeeds and /stream_routes with protocol.name = <xrpc-protocol> is not dropped / error-logged.

Error Logs

2026/04/30 18:40:42 [error] 57836#57836: *2 [lua] config_yaml.lua:333: failed to check item data of [stream_routes] err:unknown protocol [redis] ,val: {"protocol":{"name":"redis","conf":{...}},"server_port":...,"id":1}, context: init_worker_by_lua*

Steps to Reproduce

  1. Install APISIX 3.16.0.
  2. Use deployment.role: data_plane with deployment.role_data_plane.config_provider: yaml (or any setup where apisix.enable_admin = false), and enable apisix.stream_proxy.tcp.
  3. Add an xRPC-based stream route to apisix.yaml, e.g.:
    xrpc:
      protocols:
        - name: redis
    stream_routes:
      - id: 1
        server_port: 9101
        protocol:
          name: redis
          conf:
            faults: []
    #END
  4. Start APISIX. The HTTP worker logs [error] ... failed to check item data of [stream_routes] err:unknown protocol [redis] on every init / reload. The stream worker does not log this error because it registers the xRPC schemas correctly.

The same repro reproduces on 3.16.0 with any xRPC protocol (redis, dubbo, a custom one registered in xrpc.protocols).

Suggested Fix

In apisix/stream/xrpc.lua::init, also register protocol schemas in the HTTP worker when apisix.stream_proxy is configured (mirroring the condition added to router.lua in #12996):

    if is_http
        and not local_conf.apisix.enable_admin
        and not (local_conf.apisix and local_conf.apisix.stream_proxy)
    then
        return
    end

This keeps the original optimization (don't load schema modules when they cannot possibly be used), while ensuring the HTTP-side stream_route_checker introduced by #12996 has the schemas it needs.

I'm happy to send a PR if this direction sounds right.

Environment

  • APISIX version (run apisix version): 3.16.0
  • Operating system (run uname -a): Linux ... 6.x Ubuntu 24.04
  • OpenResty / Nginx version (run openresty -V or nginx -V): openresty/1.27.1.2 (APISIX runtime 1.3.2)
  • etcd version, if relevant: n/a (yaml config_provider)
  • APISIX Dashboard version: n/a
  • Plugin runner version: n/a
  • LuaRocks version: n/a

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    📋 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions