Skip to content

fix(grpc-transcode): encode empty repeated fields as JSON arrays - #13678

Merged
AlinsRan merged 1 commit into
apache:masterfrom
AlinsRan:fix/grpc-transcode-empty-array
Jul 10, 2026
Merged

fix(grpc-transcode): encode empty repeated fields as JSON arrays#13678
AlinsRan merged 1 commit into
apache:masterfrom
AlinsRan:fix/grpc-transcode-empty-array

Conversation

@AlinsRan

@AlinsRan AlinsRan commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #11440

An empty repeated field is decoded by lua-protobuf into an empty Lua table. Lua cannot tell an empty array from an empty object, so cjson.encode emits {} where the client expects [].

lua-protobuf 0.5.3 (the version pinned in the rockspec) supports a *array default metatable. Setting it to core.json.array_mt inside compile_proto() makes pb.decode tag every repeated field as an array by itself:

pb.defaults("*array", core.json.array_mt)

Behavior with the plugin's default pb_option:

  • empty repeated fields encode as []
  • map fields keep object semantics ({}) — lua-protobuf distinguishes maps from arrays natively
  • nested repeated fields inside messages, repeated messages and map values are all covered
  • it works for both the text proto path and the binary descriptor set path

pb.defaults is bound to the active pb state, so it is set per compiled proto rather than at module load time. The same is done for the gRPC status pb state, so that an empty ErrorStatus.details is also rendered as [].

This is a pure decode-side change with no per-request cost.

An alternative implementation exists in #12649, which builds a message descriptor index from the proto and walks the decoded table on every response. Besides the per-request traversal, the numeric label/type comparisons it relies on do not match on the binary descriptor path (pb.decode of a FileDescriptorSet yields "LABEL_REPEATED" / "TYPE_MESSAGE" under the default enum_as_name), so that path is left unfixed there.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

An empty `repeated` field is decoded by lua-protobuf into an empty Lua
table, which cjson then encodes as `{}` instead of `[]`.

Set the `*array` default metatable to `core.json.array_mt` on the pb
state of each compiled proto, so lua-protobuf tags every repeated field
as an array on decode. Maps keep their object semantics, and both the
text and the binary descriptor paths are covered.

Fixes apache#11440
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 9, 2026

@membphis membphis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AlinsRan
AlinsRan merged commit c7a76b2 into apache:master Jul 10, 2026
16 checks passed
@AlinsRan
AlinsRan deleted the fix/grpc-transcode-empty-array branch July 10, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: grpc-transcode cant transcode empty array list to [] , but it did to {}

4 participants