-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
fix(auth): cooldown Antigravity credentials on invalid_grant instead of silent retry loop #4130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3734,7 +3734,18 @@ func (m *Manager) MarkResult(ctx context.Context, result Result) { | |||||||||||||||||||||||||||
| state.NextRetryAfter = nextTransientErrorRetryAfter(now) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||
| state.NextRetryAfter = time.Time{} | ||||||||||||||||||||||||||||
| if isOAuthInvalidGrantResultError(result.Error) { | ||||||||||||||||||||||||||||
| if disableCooling { | ||||||||||||||||||||||||||||
| state.NextRetryAfter = time.Time{} | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| next := now.Add(30 * time.Minute) | ||||||||||||||||||||||||||||
| state.NextRetryAfter = next | ||||||||||||||||||||||||||||
| suspendReason = "unauthorized" | ||||||||||||||||||||||||||||
| shouldSuspendModel = true | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| state.NextRetryAfter = time.Time{} | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
@@ -3983,6 +3994,20 @@ func isUnauthorizedError(err error) bool { | |||||||||||||||||||||||||||
| return strings.Contains(raw, "status 401") || strings.Contains(raw, "401 unauthorized") | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // isOAuthInvalidGrantMessage checks whether an error message indicates an OAuth | ||||||||||||||||||||||||||||
| // invalid_grant failure (revoked or expired refresh token). These are credential-level | ||||||||||||||||||||||||||||
| // errors that should be cooled down, not treated as invalid request payloads. | ||||||||||||||||||||||||||||
| func isOAuthInvalidGrantMessage(msg string) bool { | ||||||||||||||||||||||||||||
| return strings.Contains(msg, "invalid_grant") | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+4002
to
+4004
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should perform a case-insensitive check when looking for the
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func isOAuthInvalidGrantResultError(err *Error) bool { | ||||||||||||||||||||||||||||
| if err == nil { | ||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return isOAuthInvalidGrantMessage(err.Message) || isOAuthInvalidGrantMessage(err.Code) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+4006
to
+4011
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of manually checking both
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func hasUnauthorizedAuthFailure(auth *Auth) bool { | ||||||||||||||||||||||||||||
| if auth == nil || auth.LastError == nil { | ||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||
|
|
@@ -4152,6 +4177,9 @@ func isRequestInvalidError(err error) bool { | |||||||||||||||||||||||||||
| switch status { | ||||||||||||||||||||||||||||
| case http.StatusBadRequest: | ||||||||||||||||||||||||||||
| msg := err.Error() | ||||||||||||||||||||||||||||
| if isOAuthInvalidGrantMessage(msg) { | ||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return strings.Contains(msg, "invalid_request_error") || | ||||||||||||||||||||||||||||
| strings.Contains(msg, "INVALID_ARGUMENT") || | ||||||||||||||||||||||||||||
| strings.Contains(msg, "FAILED_PRECONDITION") | ||||||||||||||||||||||||||||
|
|
@@ -4241,7 +4269,12 @@ func applyAuthFailureState(auth *Auth, resultErr *Error, retryAfter *time.Durati | |||||||||||||||||||||||||||
| auth.NextRetryAfter = nextTransientErrorRetryAfter(now) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||
| if auth.StatusMessage == "" { | ||||||||||||||||||||||||||||
| if resultErr != nil && isOAuthInvalidGrantMessage(resultErr.Error()) { | ||||||||||||||||||||||||||||
| auth.StatusMessage = "unauthorized" | ||||||||||||||||||||||||||||
| if !disableCooling { | ||||||||||||||||||||||||||||
| auth.NextRetryAfter = now.Add(30 * time.Minute) | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+4274
to
+4280
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When
Suggested change
|
||||||||||||||||||||||||||||
| } else if auth.StatusMessage == "" { | ||||||||||||||||||||||||||||
| auth.StatusMessage = "request failed" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a revoked Antigravity refresh token returns
invalid_grantfor one model, this only records the cooldown on that model state and suspends that single auth/model pair.isAuthBlockedForModeltreats the same auth as available for a different requested model when that model has no state, so the banned credential can still be selected for every other model and recreate the retry/failover loop per model. Sinceinvalid_grantis credential-level, block the auth across models rather than onlyresult.Model.Useful? React with 👍 / 👎.