fix(consul): tolerate null Service.Meta in fetch_services_from_server#13258
Merged
Baoyuantop merged 3 commits intoapache:masterfrom Apr 21, 2026
Merged
fix(consul): tolerate null Service.Meta in fetch_services_from_server#13258Baoyuantop merged 3 commits intoapache:masterfrom
Baoyuantop merged 3 commits intoapache:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a crash in the Consul discovery client when Consul returns "Meta": null (decoded by cjson as cjson.null userdata) by guarding metadata iteration with a type(...) == "table" check, and adds a regression test for this scenario.
Changes:
- Guard
next(node.Service.Meta)behindtype(node.Service.Meta) == "table"whenpreserve_metadata=true. - Add a new test that registers a real Consul service without
Metaand verifiesfetch_services_from_serverdoes not error and returnsmetadata == nil.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
apisix/discovery/consul/client.lua |
Prevents next() from being called on cjson.null userdata when Service.Meta is null. |
t/discovery/consul.t |
Adds a regression test covering Consul services registered without Meta. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
When a consul service is registered without metadata, the agent returns "Meta": null in the catalog response. cjson decodes that as a userdata sentinel (cjson.null) which is truthy but not a table, so the existing guard `node.Service.Meta and next(node.Service.Meta)` calls next() on userdata and aborts the whole catalog scan with: bad argument #1 to 'next' (table expected, got userdata) The discovery worker never recovers and no upstream nodes are produced. Use `type(node.Service.Meta) == "table"` so cjson.null is treated as absent metadata. Adds a regression test that registers a metadata-less service and calls fetch_services_from_server directly with preserve_metadata=true.
7ef4c3a to
6a5144c
Compare
membphis
approved these changes
Apr 21, 2026
shreemaan-abhishek
approved these changes
Apr 21, 2026
Baoyuantop
approved these changes
Apr 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Fix a crash in the Consul service discovery worker when a registered service has no metadata.
Why
When
consul services registeris used withoutmeta, the agent's catalog API returns"Meta": null. cjson decodes JSON null as a userdata sentinel (cjson.null), which is truthy but not a table. The current guard atapisix/discovery/consul/client.lua:415:passes the truthiness check, then calls
next()on userdata and aborts the entire catalog scan with:The discovery worker never recovers — no nodes are produced for any service in that response, so all upstreams resolved through Consul end up empty until the worker is restarted (and even then it crashes again on the next scrape).
This was introduced by #13230 which extracted
client.luaand added the newpreserve_metadatapath; older code didn't iterateService.Meta.Fix
Use
type(node.Service.Meta) == "table"instead of relying on truthiness, socjson.nullis treated as "no metadata" (same as the field being absent).Test
Added a regression test (
t/discovery/consul.tTEST 14) that:Metaconsul_client.fetch_services_from_serverdirectly withpreserve_metadata=truemetadata == nilThe test fails on master with the userdata error and passes with the fix.