diff --git a/backend/internal/handler/gateway_handler.go b/backend/internal/handler/gateway_handler.go index 831029c4..b5250aad 100644 --- a/backend/internal/handler/gateway_handler.go +++ b/backend/internal/handler/gateway_handler.go @@ -1219,6 +1219,10 @@ func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *se } } + // 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误 + upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody) + service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "") + // 使用默认的错误映射 status, errType, errMsg := h.mapUpstreamError(statusCode) h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted) @@ -1227,6 +1231,7 @@ func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *se // handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况 func (h *GatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) { status, errType, errMsg := h.mapUpstreamError(statusCode) + service.SetOpsUpstreamError(c, statusCode, errMsg, "") h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted) } diff --git a/backend/internal/handler/gemini_v1beta_handler.go b/backend/internal/handler/gemini_v1beta_handler.go index cfe80911..fb231898 100644 --- a/backend/internal/handler/gemini_v1beta_handler.go +++ b/backend/internal/handler/gemini_v1beta_handler.go @@ -593,6 +593,10 @@ func (h *GatewayHandler) handleGeminiFailoverExhausted(c *gin.Context, failoverE } } + // 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误 + upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody) + service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "") + // 使用默认的错误映射 status, message := mapGeminiUpstreamError(statusCode) googleError(c, status, message) diff --git a/backend/internal/handler/openai_gateway_handler.go b/backend/internal/handler/openai_gateway_handler.go index c681e61d..ec957feb 100644 --- a/backend/internal/handler/openai_gateway_handler.go +++ b/backend/internal/handler/openai_gateway_handler.go @@ -1435,6 +1435,10 @@ func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, failoverE } } + // 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误 + upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody) + service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "") + // 使用默认的错误映射 status, errType, errMsg := h.mapUpstreamError(statusCode) h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted) @@ -1443,6 +1447,7 @@ func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, failoverE // handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况 func (h *OpenAIGatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) { status, errType, errMsg := h.mapUpstreamError(statusCode) + service.SetOpsUpstreamError(c, statusCode, errMsg, "") h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted) } diff --git a/backend/internal/handler/sora_gateway_handler.go b/backend/internal/handler/sora_gateway_handler.go index dc301ce1..cc1b1c0b 100644 --- a/backend/internal/handler/sora_gateway_handler.go +++ b/backend/internal/handler/sora_gateway_handler.go @@ -484,6 +484,9 @@ func (h *SoraGatewayHandler) handleConcurrencyError(c *gin.Context, err error, s } func (h *SoraGatewayHandler) handleFailoverExhausted(c *gin.Context, statusCode int, responseHeaders http.Header, responseBody []byte, streamStarted bool) { + upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody) + service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "") + status, errType, errMsg := h.mapUpstreamError(statusCode, responseHeaders, responseBody) h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted) } diff --git a/backend/internal/service/ops_upstream_context.go b/backend/internal/service/ops_upstream_context.go index 21e09c43..9adf5896 100644 --- a/backend/internal/service/ops_upstream_context.go +++ b/backend/internal/service/ops_upstream_context.go @@ -53,6 +53,13 @@ func SetOpsLatencyMs(c *gin.Context, key string, value int64) { c.Set(key, value) } +// SetOpsUpstreamError is the exported wrapper for setOpsUpstreamError, used by +// handler-layer code (e.g. failover-exhausted paths) that needs to record the +// original upstream status code before mapping it to a client-facing code. +func SetOpsUpstreamError(c *gin.Context, upstreamStatusCode int, upstreamMessage, upstreamDetail string) { + setOpsUpstreamError(c, upstreamStatusCode, upstreamMessage, upstreamDetail) +} + func setOpsUpstreamError(c *gin.Context, upstreamStatusCode int, upstreamMessage, upstreamDetail string) { if c == nil { return