From 233be6272a8f64d229f8bfa191d80d84feba4c8b Mon Sep 17 00:00:00 2001 From: sususu98 Date: Mon, 2 Feb 2026 14:52:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(auth):=20400=20invalid=5Frequest=5Ferror=20?= =?UTF-8?q?=E7=AB=8B=E5=8D=B3=E8=BF=94=E5=9B=9E=E4=B8=8D=E5=86=8D=E9=87=8D?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当上游返回 400 Bad Request 且错误消息包含 invalid_request_error 时, 表示请求本身格式错误,切换账户不会改变结果。 修改: - 添加 isRequestInvalidError 判定函数 - 内层循环遇到此错误立即返回,不遍历其他账户 - 外层循环不再对此类错误进行重试 --- sdk/cliproxy/auth/conductor.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sdk/cliproxy/auth/conductor.go b/sdk/cliproxy/auth/conductor.go index 3a64c8c3..b96ccdfb 100644 --- a/sdk/cliproxy/auth/conductor.go +++ b/sdk/cliproxy/auth/conductor.go @@ -607,6 +607,9 @@ func (m *Manager) executeMixedOnce(ctx context.Context, providers []string, req result.RetryAfter = ra } m.MarkResult(execCtx, result) + if isRequestInvalidError(errExec) { + return cliproxyexecutor.Response{}, errExec + } lastErr = errExec continue } @@ -660,6 +663,9 @@ func (m *Manager) executeCountMixedOnce(ctx context.Context, providers []string, result.RetryAfter = ra } m.MarkResult(execCtx, result) + if isRequestInvalidError(errExec) { + return cliproxyexecutor.Response{}, errExec + } lastErr = errExec continue } @@ -711,6 +717,9 @@ func (m *Manager) executeStreamMixedOnce(ctx context.Context, providers []string result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: false, Error: rerr} result.RetryAfter = retryAfterFromError(errStream) m.MarkResult(execCtx, result) + if isRequestInvalidError(errStream) { + return nil, errStream + } lastErr = errStream continue } @@ -1110,6 +1119,9 @@ func (m *Manager) shouldRetryAfterError(err error, attempt int, providers []stri if status := statusCodeFromError(err); status == http.StatusOK { return 0, false } + if isRequestInvalidError(err) { + return 0, false + } wait, found := m.closestCooldownWait(providers, model, attempt) if !found || wait > maxWait { return 0, false @@ -1430,6 +1442,21 @@ func statusCodeFromResult(err *Error) int { return err.StatusCode() } +// isRequestInvalidError returns true if the error represents a client request +// error that should not be retried. Specifically, it checks for 400 Bad Request +// with "invalid_request_error" in the message, indicating the request itself is +// malformed and switching to a different auth will not help. +func isRequestInvalidError(err error) bool { + if err == nil { + return false + } + status := statusCodeFromError(err) + if status != http.StatusBadRequest { + return false + } + return strings.Contains(err.Error(), "invalid_request_error") +} + func applyAuthFailureState(auth *Auth, resultErr *Error, retryAfter *time.Duration, now time.Time) { if auth == nil { return