#13944·apisix

bug: ai-prompt-guard returns an empty 200 instead of proxying when no content is selected for checking

Author: SantoshkumarpuppalaCreated Sep 14, 2026Updated Sep 16, 2026

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_roles left at its default false (ai-prompt-guard.lua:38-41) and no user message in the request, e.g. only a system message. 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 input as an array of strings. ai-protocols/openai-embeddings.lua:109-117 only collects a string input, 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

  1. Use the route from TEST 8 in t/plugin/ai-prompt-guard.t (only allow_patterns set; match_all_roles at its default).
  2. Add --- response_body with hello world to TEST 9.
  3. Run prove t/plugin/ai-prompt-guard.t — TEST 9 should fail on current master, and pass once return 200 becomes return.

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.