When handling optional/nil values, treat nil as a real input only if it’s reachable; otherwise remove dead checks. More importantly, enforce clear contracts for types/shapes so nil never reaches code paths that assume a table/string.
Practical rules: 1) Guard before indexing/iteration
x[y], x:method(), pairs(x), or table.concat.2) Preserve function return contracts
{} instead of nil if the caller does pairs(...)).3) Match conditional construction with downstream access
body.index), ensure later code doesn’t unconditionally access it. Either build the required structure in all branches or branch the downstream logic too.4) Prefer explicit fallback over misleading nil branches
fetch_secrets(...) or upstream_obj) to keep behavior correct in failure cases.5) Tests: avoid vacuous “truthy encryption”
nil ~= "plaintext" will incorrectly pass.Example patterns:
-- 1) fallback instead of dead nil-check
local new_upstream_ssl = apisix_secret.fetch_secrets(upstream_ssl, true)
new_upstream_ssl = new_upstream_ssl or upstream_ssl
-- 2) return safe type for iteration
local function names_from_proto(proto_obj)
local names = {}
if type(proto_obj) ~= "table" then
return names
end
-- ... fill names
return names
end
-- 3) nil-guard before method call
local data = core.request.get_body()
local ticket = data and data:match("<samlp:SessionIndex>(.+)</samlp:SessionIndex>")
-- 5) test: require non-empty string
local conf = get_conf()
local v = conf.client_rsa_private_key
assert(type(v) == "string" and v ~= "" and v ~= "plaintext")
Enter the URL of a public GitHub repository