bug: ai-prompt-guard returns an empty 200 instead of proxying when no content is selected for checking
Raised on #13731 at the maintainers' request, split out from that docs PR.
Current Behavior
When the set of messages selected for checking is empty, ai-prompt-guard returns 200 from _M.access (apisix/plugins/ai-prompt-guard.lua:162-164). plugin.lua:1406-1419 hands any non-nil code to core.response.exit, and core/response.lua:126-134 calls ngx_exit(code) for any code — the >= 400 branch only adds tracing. The client gets an empty 200 and the upstream is never called.
Two ordinary requests reach it:
match_all_rolesleft at its defaultfalse(ai-prompt-guard.lua:38-41) and nousermessage in the request, e.g. only asystemmessage. Non-user messages are filtered out (:152-154), the list is empty, and the request is answered with an empty 200. No non-default configuration is needed to reach this.- Embeddings with
inputas an array of strings.ai-protocols/openai-embeddings.lua:109-117only collects a stringinput, so an array yields{}.
The repo already uses both meanings of the return value: cors.lua:338-339 returns 200 deliberately to end an OPTIONS preflight, and ai-lakera-guard.lua:104-105 uses a bare return for the same "no messages" condition and lets the request continue.
Nothing is logged: the warn at plugin.lua:1408-1409 only fires for codes >= 400.
Expected Behavior
Nothing to check should mean pass through to the upstream, as ai-lakera-guard does. The fix is return instead of return 200.
The tests don't catch this. t/plugin/ai-prompt-guard.t TEST 9 (line 243, "send request with bad word and it will pass for non user") is exactly the first case — its route, from TEST 8, sets only allow_patterns and leaves match_all_roles at the default — and it asserts neither --- response_body nor --- error_code, so it passes whether the request was proxied or cut off. TESTs 3, 6, 14, 20, 23 and 26 have the same gap. Adding --- response_body / hello world (t/lib/server.lua:74-79) would make them discriminate, following t/plugin/ai-lakera-guard.t, which already asserts --- error_code: 200 with --- response_body_like on its allow paths.
Error Logs
None — see the note on logging above.
Steps to Reproduce
- Use the route from TEST 8 in
t/plugin/ai-prompt-guard.t(onlyallow_patternsset;match_all_rolesat its default). - Add
--- response_bodywithhello worldto TEST 9. - Run
prove t/plugin/ai-prompt-guard.t— TEST 9 should fail on currentmaster, and pass oncereturn 200becomesreturn.
Environment
master at d13105e17 (2026-09-14). Traced from source, not run — I don't have an APISIX test environment set up, so treat the reproduction above as the expected result rather than an observed one.
Happy to open the PR with the one-line fix and the test assertions.
Source: apache/apisix