Skip to content

bug: oas-validator transitively installs lua-cjson 2.1.0.10 in deps/, shadowing bundled 2.1.0.11 and regressing empty_array on arm64/Apple Silicon #13593

Description

@yurkovoznyak

Update / correction: the original report said the breakage was architecture-independent. That was wrong. After further testing it reproduces only on arm64 / Apple Silicon; amd64 is unaffected. The underlying empty_array bug is also already fixed in lua-cjson 2.1.0.11. The remaining APISIX issue is that the image ships an older lua-cjson (2.1.0.10) in deps/ that shadows the bundled 2.1.0.11. Details below have been corrected accordingly.

Current Behavior

APISIX 3.17.0 ships lua-cjson 2.1.0.10 in /usr/local/apisix/deps/lib/lua/5.1/cjson.so, which shadows OpenResty's bundled 2.1.0.11 in the worker's lua_package_cpath. lua-cjson 2.1.0.10 predates the fix for openresty/lua-cjson#81 / #82 (commit 92cebdc, "compare light userdata with masked address"), so on arm64 / Apple Silicon cjson.empty_array is not recognized by the encoder and serializes to nothing instead of []:

require("cjson").encode({ x = require("cjson").empty_array })
-- arm64 / Apple Silicon, deps cjson 2.1.0.10: {"x":}   <-- malformed, value dropped
-- expected (and on amd64, or with bundled 2.1.0.11):   {"x":[]}

This is architecture-specific: it manifests on arm64/Apple Silicon only. On amd64 the same 2.1.0.10 encodes empty_array correctly. Any plugin relying on the cjson.empty_array sentinel produces invalid JSON on arm64, with no error raised.

The new oas-validator plugin's dependency lua-resty-openapi-validator = 1.0.5-1 (new in 3.17.0, absent in 3.16.0) declares an unpinned lua-cjson, which is what causes luarocks to install 2.1.0.10 into deps/.

Expected Behavior

cjson.empty_array encodes to [] on all architectures. The image should not ship a deps/ lua-cjson that is older than (and shadows) the OpenResty-bundled one.

Error Logs

No error is raised — the encoder silently drops the sentinel value, yielding malformed JSON.

Steps to Reproduce

On an arm64 / Apple Silicon host (Docker Desktop, arm64 nodes):

  1. docker pull apache/apisix:3.17.0-ubuntu

  2. Run the bundled OpenResty against the deps/ cjson (what a worker loads):

    docker run --rm --entrypoint /usr/local/openresty/bin/resty \
      apache/apisix:3.17.0-ubuntu -e \
      'package.cpath="/usr/local/apisix/deps/lib/lua/5.1/?.so;"..package.cpath
       local c=require"cjson"
       print(c._VERSION, c.encode({x=c.empty_array}))'
    # arm64: 2.1.0.10   {"x":}        (expected: {"x":[]})
    # amd64: 2.1.0.10   {"x":[]}      (works)
  3. Contrast with the bundled cjson (works on both arches):

    docker run --rm --entrypoint /usr/local/openresty/bin/resty \
      apache/apisix:3.17.0-ubuntu -e \
      'package.cpath="/usr/local/openresty/lualib/?.so;"..package.cpath
       local c=require"cjson"
       print(c._VERSION, c.encode({x=c.empty_array}))'
    # => 2.1.0.11   {"x":[]}
  4. Confirm the two cjson copies and which rock pulled in the old one:

    docker run --rm --entrypoint sh apache/apisix:3.17.0-ubuntu -c \
      'find / -name "cjson*.so" 2>/dev/null'
    # /usr/local/apisix/deps/lib/lua/5.1/cjson.so   (2.1.0.10, luarocks, via lua-resty-openapi-validator)
    # /usr/local/openresty/lualib/cjson.so          (2.1.0.11, bundled)

Workaround for plugin authors: setmetatable({}, cjson.array_mt) encodes to [] correctly in both versions and on both arches.

Suggested fix

Ensure the deps/ lua-cjson is not older than the bundled one — e.g. pin lua-cjson >= 2.1.0.11 in the APISIX rockspec (so the transitive dep from lua-resty-openapi-validator cannot downgrade it), or otherwise dedupe to the bundled version / prefer it in lua_package_cpath.

Environment

  • APISIX version: 3.17.0 (official apache/apisix:3.17.0-ubuntu, digest sha256:d7c01c5fc829e2f7375f8f7f2b02d29bb3d85f5069c327e61734c5bb8132a823)
  • Operating system: Ubuntu image. Reproduces on arm64 / Apple Silicon only; amd64 unaffected (verified on both via the multi-arch image).
  • OpenResty / Nginx version: openresty/1.29.2.4
  • LuaRocks: lua-cjson 2.1.0.10 installed in deps/ (via lua-resty-openapi-validator = 1.0.5-1), shadowing bundled 2.1.0.11.

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