Skip to content

Commit 1fd1a58

Browse files
StarryKiraclaude
andcommitted
fix: record original upstream status code when failover exhausted (Wei-Shaw#1128)
When all failover accounts are exhausted, handleFailoverExhausted maps the upstream status code (e.g. 403) to a client-facing code (e.g. 502) but did not write the original code to the gin context. This caused ops error logs to show the mapped code instead of the real upstream code. Call SetOpsUpstreamError before mapUpstreamError in all failover- exhausted paths so that ops_error_logger captures the true upstream status code and message. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9f6ab6b commit 1fd1a58

5 files changed

Lines changed: 24 additions & 0 deletions

File tree

backend/internal/handler/gateway_handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,10 @@ func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *se
12191219
}
12201220
}
12211221

1222+
// 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误
1223+
upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody)
1224+
service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "")
1225+
12221226
// 使用默认的错误映射
12231227
status, errType, errMsg := h.mapUpstreamError(statusCode)
12241228
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
@@ -1227,6 +1231,7 @@ func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *se
12271231
// handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况
12281232
func (h *GatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) {
12291233
status, errType, errMsg := h.mapUpstreamError(statusCode)
1234+
service.SetOpsUpstreamError(c, statusCode, errMsg, "")
12301235
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
12311236
}
12321237

backend/internal/handler/gemini_v1beta_handler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ func (h *GatewayHandler) handleGeminiFailoverExhausted(c *gin.Context, failoverE
593593
}
594594
}
595595

596+
// 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误
597+
upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody)
598+
service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "")
599+
596600
// 使用默认的错误映射
597601
status, message := mapGeminiUpstreamError(statusCode)
598602
googleError(c, status, message)

backend/internal/handler/openai_gateway_handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,10 @@ func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, failoverE
14351435
}
14361436
}
14371437

1438+
// 记录原始上游状态码,以便 ops 错误日志捕获真实的上游错误
1439+
upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody)
1440+
service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "")
1441+
14381442
// 使用默认的错误映射
14391443
status, errType, errMsg := h.mapUpstreamError(statusCode)
14401444
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
@@ -1443,6 +1447,7 @@ func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, failoverE
14431447
// handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况
14441448
func (h *OpenAIGatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) {
14451449
status, errType, errMsg := h.mapUpstreamError(statusCode)
1450+
service.SetOpsUpstreamError(c, statusCode, errMsg, "")
14461451
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
14471452
}
14481453

backend/internal/handler/sora_gateway_handler.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ func (h *SoraGatewayHandler) handleConcurrencyError(c *gin.Context, err error, s
484484
}
485485

486486
func (h *SoraGatewayHandler) handleFailoverExhausted(c *gin.Context, statusCode int, responseHeaders http.Header, responseBody []byte, streamStarted bool) {
487+
upstreamMsg := service.ExtractUpstreamErrorMessage(responseBody)
488+
service.SetOpsUpstreamError(c, statusCode, upstreamMsg, "")
489+
487490
status, errType, errMsg := h.mapUpstreamError(statusCode, responseHeaders, responseBody)
488491
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
489492
}

backend/internal/service/ops_upstream_context.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ func SetOpsLatencyMs(c *gin.Context, key string, value int64) {
5353
c.Set(key, value)
5454
}
5555

56+
// SetOpsUpstreamError is the exported wrapper for setOpsUpstreamError, used by
57+
// handler-layer code (e.g. failover-exhausted paths) that needs to record the
58+
// original upstream status code before mapping it to a client-facing code.
59+
func SetOpsUpstreamError(c *gin.Context, upstreamStatusCode int, upstreamMessage, upstreamDetail string) {
60+
setOpsUpstreamError(c, upstreamStatusCode, upstreamMessage, upstreamDetail)
61+
}
62+
5663
func setOpsUpstreamError(c *gin.Context, upstreamStatusCode int, upstreamMessage, upstreamDetail string) {
5764
if c == nil {
5865
return

0 commit comments

Comments
 (0)