From fa8f1749f50c22f5302719b670d896f0860721d7 Mon Sep 17 00:00:00 2001 From: jjaw Date: Wed, 10 Jun 2026 14:11:41 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20treat=20invalid=5Frefresh=5Ftoken=20?= =?UTF-8?q?as=20non-retryable=20/=20=E5=B0=86=20invalid=5Frefresh=5Ftoken?= =?UTF-8?q?=20=E5=88=A4=E5=AE=9A=E4=B8=BA=E4=B8=8D=E5=8F=AF=E9=87=8D?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/token_refresh_service.go | 13 +++++++------ .../internal/service/token_refresh_service_test.go | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/backend/internal/service/token_refresh_service.go b/backend/internal/service/token_refresh_service.go index c5f1991bc7..8e41036516 100644 --- a/backend/internal/service/token_refresh_service.go +++ b/backend/internal/service/token_refresh_service.go @@ -440,12 +440,13 @@ func isNonRetryableRefreshError(err error) bool { } msg := strings.ToLower(err.Error()) nonRetryable := []string{ - "invalid_grant", // refresh_token 已失效 - "refresh_token_reused", // OpenAI refresh_token 已被使用,必须重新授权 - "invalid_client", // 客户端配置错误 - "unauthorized_client", // 客户端未授权 - "access_denied", // 访问被拒绝 - "missing_project_id", // 缺少 project_id + "invalid_grant", // refresh_token 已失效 + "invalid_refresh_token", // refresh_token 无效, team 账号工作区被删除会出现 + "refresh_token_reused", // OpenAI refresh_token 已被使用,必须重新授权 + "invalid_client", // 客户端配置错误 + "unauthorized_client", // 客户端未授权 + "access_denied", // 访问被拒绝 + "missing_project_id", // 缺少 project_id "no refresh token available", } for _, needle := range nonRetryable { diff --git a/backend/internal/service/token_refresh_service_test.go b/backend/internal/service/token_refresh_service_test.go index d80b475ea3..5167456c5d 100644 --- a/backend/internal/service/token_refresh_service_test.go +++ b/backend/internal/service/token_refresh_service_test.go @@ -532,6 +532,7 @@ func TestIsNonRetryableRefreshError(t *testing.T) { {name: "network_error", err: errors.New("network timeout"), expected: false}, {name: "invalid_grant", err: errors.New("invalid_grant"), expected: true}, {name: "invalid_client", err: errors.New("invalid_client"), expected: true}, + {name: "invalid_refresh_token", err: errors.New(`OPENAI_OAUTH_TOKEN_REFRESH_FAILED: token refresh failed: status 401, body: {"error":{"code":"invalid_refresh_token"}}`), expected: true}, {name: "refresh_token_reused", err: errors.New(`OPENAI_OAUTH_TOKEN_REFRESH_FAILED: token refresh failed: status 401, body: {"error":{"code":"refresh_token_reused"}}`), expected: true}, {name: "unauthorized_client", err: errors.New("unauthorized_client"), expected: true}, {name: "access_denied", err: errors.New("access_denied"), expected: true}, From 727ac3f6893ae0d2e6b37865167b65e6745247c8 Mon Sep 17 00:00:00 2001 From: jjaw Date: Wed, 10 Jun 2026 22:32:04 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20add=20app=5Fsession=5Fterminated=20t?= =?UTF-8?q?o=20non-retryable=20refresh=20errors=20/=20=E5=B0=86=20app=5Fse?= =?UTF-8?q?ssion=5Fterminated=20=E6=B7=BB=E5=8A=A0=E5=88=B0=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E9=87=8D=E8=AF=95=E7=9A=84=E5=88=B7=E6=96=B0=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/token_refresh_service.go | 15 ++++++++------- .../service/token_refresh_service_test.go | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/internal/service/token_refresh_service.go b/backend/internal/service/token_refresh_service.go index 8e41036516..bac7e4cbed 100644 --- a/backend/internal/service/token_refresh_service.go +++ b/backend/internal/service/token_refresh_service.go @@ -440,13 +440,14 @@ func isNonRetryableRefreshError(err error) bool { } msg := strings.ToLower(err.Error()) nonRetryable := []string{ - "invalid_grant", // refresh_token 已失效 - "invalid_refresh_token", // refresh_token 无效, team 账号工作区被删除会出现 - "refresh_token_reused", // OpenAI refresh_token 已被使用,必须重新授权 - "invalid_client", // 客户端配置错误 - "unauthorized_client", // 客户端未授权 - "access_denied", // 访问被拒绝 - "missing_project_id", // 缺少 project_id + "invalid_grant", // refresh_token 已失效 + "invalid_refresh_token", // refresh_token 无效, team 账号工作区被删除会出现 + "app_session_terminated", // refresh_token team 账号工作区被删除 + "refresh_token_reused", // OpenAI refresh_token 已被使用,必须重新授权 + "invalid_client", // 客户端配置错误 + "unauthorized_client", // 客户端未授权 + "access_denied", // 访问被拒绝 + "missing_project_id", // 缺少 project_id "no refresh token available", } for _, needle := range nonRetryable { diff --git a/backend/internal/service/token_refresh_service_test.go b/backend/internal/service/token_refresh_service_test.go index 5167456c5d..24adcfb6b3 100644 --- a/backend/internal/service/token_refresh_service_test.go +++ b/backend/internal/service/token_refresh_service_test.go @@ -534,6 +534,7 @@ func TestIsNonRetryableRefreshError(t *testing.T) { {name: "invalid_client", err: errors.New("invalid_client"), expected: true}, {name: "invalid_refresh_token", err: errors.New(`OPENAI_OAUTH_TOKEN_REFRESH_FAILED: token refresh failed: status 401, body: {"error":{"code":"invalid_refresh_token"}}`), expected: true}, {name: "refresh_token_reused", err: errors.New(`OPENAI_OAUTH_TOKEN_REFRESH_FAILED: token refresh failed: status 401, body: {"error":{"code":"refresh_token_reused"}}`), expected: true}, + {name: "app_session_terminated", err: errors.New(`OPENAI_OAUTH_TOKEN_REFRESH_FAILED: token refresh failed: status 401, body: {"error": {"code": "app_session_terminated"}}`), expected: true}, {name: "unauthorized_client", err: errors.New("unauthorized_client"), expected: true}, {name: "access_denied", err: errors.New("access_denied"), expected: true}, {name: "no_refresh_token", err: errors.New("no refresh token available"), expected: true},