This is an automated email from the ASF dual-hosted git repository.

nic-6443 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new e99fb63fe fix(ai-proxy): map upstream LLM timeouts to 504 instead of 
500 (#13481)
e99fb63fe is described below

commit e99fb63feda3a12320d29cdba4dbfe089d9eea38
Author: Nic <[email protected]>
AuthorDate: Tue Jun 9 14:04:55 2026 +0800

    fix(ai-proxy): map upstream LLM timeouts to 504 instead of 500 (#13481)
---
 apisix/plugins/ai-transport/http.lua |  4 ++-
 t/plugin/ai-transport-http.t         | 65 ++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/apisix/plugins/ai-transport/http.lua 
b/apisix/plugins/ai-transport/http.lua
index d92ecf5ba..eb7efc34b 100644
--- a/apisix/plugins/ai-transport/http.lua
+++ b/apisix/plugins/ai-transport/http.lua
@@ -36,8 +36,10 @@ local rapidjson_null = rapidjson.null
 
 
 --- Map network errors to HTTP status codes.
+-- Cosocket timers report "timeout"; OS errno (ETIMEDOUT) and the resolver
+-- report "... timed out", so both spellings must be matched.
 function _M.handle_error(err)
-    if core.string.find(err, "timeout") then
+    if core.string.find(err, "timeout") or core.string.find(err, "timed out") 
then
         return 504
     end
     return 500
diff --git a/t/plugin/ai-transport-http.t b/t/plugin/ai-transport-http.t
index a2cb27883..b47516493 100644
--- a/t/plugin/ai-transport-http.t
+++ b/t/plugin/ai-transport-http.t
@@ -288,3 +288,68 @@ failed to encode AI request body with rapidjson:
 
{"messages":[{"content":"hi","role":"user"},{"content":"hello","role":"assistant"}],"model":"m"}
 --- no_error_log
 failed to encode AI request body with rapidjson:
+
+
+
+=== TEST 6: connect timeout ("Operation timed out") maps to 504
+--- config
+    location /t {
+        content_by_lua_block {
+            local orig_http = package.loaded["resty.http"]
+            local orig_transport = 
package.loaded["apisix.plugins.ai-transport.http"]
+
+            package.loaded["resty.http"] = {
+                new = function()
+                    return {
+                        set_timeout = function() end,
+                        connect = function() return nil, "Operation timed out" 
end,
+                    }
+                end,
+            }
+
+            package.loaded["apisix.plugins.ai-transport.http"] = nil
+            local transport = require("apisix.plugins.ai-transport.http")
+            local res, err = transport.request({
+                host = "127.0.0.1",
+                port = 80,
+                path = "/",
+                body = {model = "m"},
+            }, 1000)
+            ngx.say("err: ", err)
+            ngx.say("status: ", transport.handle_error(err))
+
+            package.loaded["resty.http"] = orig_http
+            package.loaded["apisix.plugins.ai-transport.http"] = orig_transport
+        }
+    }
+--- response_body
+err: connect: Operation timed out
+status: 504
+
+
+
+=== TEST 7: handle_error maps every timeout spelling to 504, others to 500
+--- config
+    location /t {
+        content_by_lua_block {
+            local transport = require("apisix.plugins.ai-transport.http")
+            local cases = {
+                "connect: timeout",
+                "connect: connection timed out",
+                "connect: operation timed out",
+                "connect: Operation timed out",
+                "request: connection refused",
+                "request: connection reset by peer",
+            }
+            for _, e in ipairs(cases) do
+                ngx.say(e, " => ", transport.handle_error(e))
+            end
+        }
+    }
+--- response_body
+connect: timeout => 504
+connect: connection timed out => 504
+connect: operation timed out => 504
+connect: Operation timed out => 504
+request: connection refused => 500
+request: connection reset by peer => 500

Reply via email to