Skip to content

fix(cli): remove stale key after resolving env var in config keys#12885

Open
pronchakov wants to merge 3 commits into
apache:masterfrom
pronchakov:issue/12884/pulling-env-vars-in-yaml-keys-works-but-results-in-error-message-in-logs
Open

fix(cli): remove stale key after resolving env var in config keys#12885
pronchakov wants to merge 3 commits into
apache:masterfrom
pronchakov:issue/12884/pulling-env-vars-in-yaml-keys-works-but-results-in-error-message-in-logs

Conversation

@pronchakov

Copy link
Copy Markdown

Description

There is a little bug in function local function resolve_conf_var(conf) in cli/file.lua
conf.key = nil deletes entry from conf with name "key"
but after variable substitution, old entry with name contained in variable key should be removed.
so it needs to be rewritten to conf[key] = nil

conf.key = nil results in adding entry with resolved variable to conf, but doesn't remove entry with unresolved variable name.
In case of using it in routes->upstream->nodes it results in two node entries. one is correct and one with unresolved variable name in it, that results in dns error in logs. I suppose that another places will result in different consequences.

Which issue(s) this PR fixes:

Fixes #12884

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)

@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. bug Something isn't working labels Jan 9, 2026
@Baoyuantop

Copy link
Copy Markdown
Contributor

Hi @pronchakov, can you add corresponding tests for this fix?

@pronchakov

Copy link
Copy Markdown
Author

Hi @pronchakov, can you add corresponding tests for this fix?

Ok, I'll add some tests.

@Baoyuantop Baoyuantop added the wait for update wait for the author's response in this issue/PR label Jan 20, 2026

@moonming moonming 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.

Hi @pronchakov, thank you for catching this bug!

This is a clear and correct fix — conf.key = nil should be conf[key] = nil. The current code sets a literal field named key to nil instead of deleting the dynamic key. Great catch!

One request: Could you please add a test case that verifies this behavior? Something like:

  • Define a route/config where a key name contains an environment variable reference (e.g., \${{ENV_KEY_NAME}})
  • Verify that after resolution, the old key is properly removed and the new key exists

This is a one-line fix with clear correctness, so once the test is added, this should be ready to merge. Thank you!

@Baoyuantop

Copy link
Copy Markdown
Contributor

Hi @pronchakov, following up on the previous review comments. Please let us know if you have any updates. Thank you.

Comment thread apisix/cli/file.lua Outdated
AlinsRan added 2 commits July 8, 2026 08:36
Inserting the resolved key while iterating conf with pairs() is undefined
behavior; the new_keys guard only masked one of its symptoms. Collect the
renames and apply them after the loop instead.

Also add a standalone JSON test, which is the only remaining caller of
resolve_conf_var() that reproduces the upstream node key case from apache#12884.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Jul 10, 2026
@AlinsRan

AlinsRan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@pronchakov I pushed two commits to your branch — one reshapes the fix, so here's why.

The one-char fix isn't enough. conf[key] = nil is right, but the delete and the insert (conf[new_key] = val) both stay inside the pairs() loop. Inserting into a table you're iterating with pairs() is undefined in Lua — LuaJIT may raise invalid key to 'next', skip entries, or revisit them. new_keys only papered over one symptom (the new key being visited again).

new_keys also has a bug of its own: the guard if new_keys[key] is keyed on the resolved name, so if a resolved key collides with another key already in the same table, that entry gets skipped wholesale and its own placeholders never get substituted.

New shape: collect renames during the traversal, apply them after. No insert while iterating, so new_keys and the goto both disappear.

    if renamed_keys then
        for key, new_key in pairs(renamed_keys) do
            conf[new_key] = conf[key]
            conf[key] = nil
        end
    end

Tests. Yours covers the config.yaml caller. I added t/config-center-json/route-upstream.t TEST 8: env var as an upstream node key in standalone apisix.json, the closest repro of #12884 that still reaches resolve_conf_var() on master (the apisix.yaml path stopped calling it after #13078).

Worth noting what it exposes — with the pre-fix code the request doesn't just log a DNS error, it times out. Roundrobin hits the stale unresolved node and hangs. The impact in standalone JSON is heavier than the issue suggests.

Verified: luacheck clean, TEST 8 passes with the fix and fails without it, t/core/config.t still green. I also retitled the PR.

@AlinsRan AlinsRan changed the title fix: old entry with unresolved variable name doesn't deletes from config table after var value substitution fix(cli): remove stale key after resolving env var in config keys Jul 10, 2026
@AlinsRan AlinsRan requested a review from moonming July 10, 2026 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:M This PR changes 30-99 lines, ignoring generated files. wait for update wait for the author's response in this issue/PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: pulling env vars in yaml keys works, but results in error message in logs

5 participants