invalid_grant и автоматическое отключение аккаунта: почему это происходит, как восстановить
Чему вы научитесь
- При виде
invalid_grantзнать, к какой категории проблем refresh_token это относится - Понять "почему аккаунт внезапно недоступен": при каких условиях он будет автоматически отключен, как система обрабатывает после отключения
- Восстановить аккаунт кратчайшим путем и подтвердить, что восстановление вступило в силу для работающего Proxy
Ваши симптомы
- Вызов локального Proxy внезапно не удается, в сообщении об ошибке появляется
invalid_grant - Аккаунт явно есть в списке Accounts, но Proxy постоянно пропускает его (или вы чувствуете, что "он больше не используется")
- При небольшом количестве аккаунтов, после одной
invalid_grant, общая доступность значительно ухудшается
Что такое invalid_grant?
invalid_grant - это тип ошибки, возвращаемый Google OAuth при обновлении access_token. Для Antigravity Tools это означает, что refresh_token определенного аккаунта, скорее всего, уже отозван или истек, повторные попытки только приведут к постоянным сбоям, поэтому система пометит этот аккаунт как недоступный и удалит его из пула прокси.
Основная идея: система не "временно пропускает", а "постоянно отключает"
Когда Proxy обнаруживает, что строка ошибки при обновлении токена содержит invalid_grant, он делает две вещи:
- Записать аккаунт как disabled (пишется на диск в JSON аккаунта)
- Удалить аккаунт из пула токенов памяти (избегает повторного выбора одного и того же проблемного аккаунта)
Это причина, по которой вы видите "аккаунт есть, но Proxy больше не использует его".
disabled vs proxy_disabled
disabled=true: аккаунт "полностью отключен" (типичная причина -invalid_grant). При загрузке пула аккаунтов он сразу пропускается.proxy_disabled=true: аккаунт только "недоступен для Proxy" (ручное отключение / массовая операция / логика защиты квоты), семантика отличается.
Эти два состояния оцениваются отдельно при загрузке пула аккаунтов: сначала оценивается disabled, затем оценка защиты квоты и proxy_disabled.
Делайте вместе со мной
Шаг 1: Подтвердите, что это invalid_grant, вызванный обновлением refresh_token
Зачем: invalid_grant может появиться в нескольких цепочках вызовов, но "автоматическое отключение" в этом проекте срабатывает только при сбое обновления access_token.
В логах Proxy вы увидите похожую ошибку (ключевое слово: Token 刷新失败 + invalid_grant):
Token 刷新失败 (<email>): <...invalid_grant...>,尝试下一个账号
Disabling account due to invalid_grant (<email>): refresh_token likely revoked/expiredВы должны увидеть: После появления invalid_grant у одного и того же аккаунта, он скоро перестанет выбираться (потому что он удален из пула токенов).
Шаг 2: Проверьте поле disabled в файле аккаунта (опционально, но наиболее точно)
Зачем: Автоматическое отключение "пишется на диск", после подтверждения содержимого файла вы можете исключить неправильное суждение "только временная ротация".
Файл аккаунта находится в каталоге accounts/ каталога данных приложения (местоположение каталога данных см. Первый запуск обязательно: каталог данных, логи, системный трей и автозапуск). Когда аккаунт отключен, в файле появятся эти три поля:
{
"disabled": true,
"disabled_at": 1700000000,
"disabled_reason": "invalid_grant: ..."
}Вы должны увидеть: disabled равно true, и disabled_reason содержит префикс invalid_grant:.
Шаг 3: Восстановите аккаунт (рекомендуемый способ: повторно добавить тот же аккаунт)
Зачем: "Восстановление" в этом проекте - это не нажать переключатель вручную в Proxy, а запустить автоматическую разблокировку путем "явного обновления токена".
Перейдите на страницу Accounts, повторно добавьте аккаунт с вашими новыми учетными данными (выберите один из двух способов):
- Пройдите процесс авторизации OAuth снова (см. Добавление аккаунта: двусторонний канал OAuth/Refresh Token и лучшие практики)
- Добавьте снова с новым
refresh_token(система возьмет почту, возвращенную Google, в качестве критерия для upsert)
Когда система обнаруживает, что refresh_token или access_token этого upsert отличается от старого значения, и этот аккаунт ранее был в состоянии disabled=true, она автоматически очистит:
disableddisabled_reasondisabled_at
Вы должны увидеть: Аккаунт больше не находится в состоянии disabled, и (если Proxy работает) пул аккаунтов будет автоматически перезагружен, чтобы восстановление вступило в силу немедленно.
Шаг 4: Подтвердите, что восстановление вступило в силу для Proxy
Зачем: Если у вас только один аккаунт, или другие аккаунты также недоступны, после восстановления вы должны сразу увидеть "доступность вернулась".
Метод проверки:
- Сделайте запрос, который вызовет обновление токена (например, дождитесь, пока токен не истечет, затем запросите)
- Наблюдайте, в логах больше не появляется подсказка "пропустить disabled аккаунт"
Вы должны увидеть: Запрос проходит нормально, и в логах больше не появляется процесс отключения invalid_grant для этого аккаунта.
Предупреждения о типичных ошибках
❌ Считать disabled как "временная ротация"
Если вы только смотрите в UI "аккаунт есть", легко ошибочно судить "система временно не использует его". Но disabled=true записано на диск, после перезапуска оно все равно действует.
❌ Только пополнять access_token, не обновлять refresh_token
Точка срабатывания invalid_grant - это refresh_token, используемый при обновлении access_token. Если вы только временно получили еще работающий access_token, но refresh_token все еще недействителен, позже он снова вызовет отключение.
Контрольная точка ✅
- [ ] Вы можете подтвердить в логах, что
invalid_grantпроисходит от сбоя обновления refresh_token - [ ] Вы знаете семантическую разницу между
disabledиproxy_disabled - [ ] Вы можете восстановить аккаунт, повторно добавив его (OAuth или refresh_token)
- [ ] Вы можете подтвердить, что восстановление вступило в силу для работающего Proxy
Краткий итог урока
- При срабатывании
invalid_grant, Proxy запишет аккаунт как disabled на диск и удалит его из пула токенов, избегая постоянных сбоев - Ключ к восстановлению - это "явное обновление токена" (повторный OAuth или добавление снова с новым refresh_token), система автоматически очистит поля
disabled_* - JSON аккаунта в каталоге данных - самый авторитетный источник состояния (отключение/причина/время все внутри)
Следующий урок预告
Следующий урок мы изучим 401/Сбой аутентификации: auth_mode, совместимость заголовков и контрольный список конфигурации клиента.
Вы узнаете:
- 401 обычно в каком слое "режим/Key/заголовок" не совпадает
- Какие заголовки аутентификации должны нести разные клиенты
- Как с кратчайшим путем проверить и исправить самостоятельно
Приложение: Справка по исходному коду
Нажмите, чтобы увидеть местоположение исходного кода
Обновлено: 2026-01-23
| Функция | Путь к файлу | Строки |
|---|---|---|
| Объяснение дизайна: проблема invalid_grant и поведение изменений | docs/proxy-invalid-grant.md | 1-52 |
При загрузке пула аккаунтов пропустить disabled=true | src-tauri/src/proxy/token_manager.rs | 70-158 |
При сбое обновления токена распознать invalid_grant и отключить аккаунт | src-tauri/src/proxy/token_manager.rs | 840-890 |
Записать на диск disabled/disabled_at/disabled_reason и удалить из памяти | src-tauri/src/proxy/token_manager.rs | 942-969 |
Обрезка disabled_reason (избегает раздувания файла аккаунта) | src-tauri/src/proxy/token_manager.rs | 1464-1471 |
При upsert автоматически очистить disabled_* (изменение токена считается пользователем уже исправившим учетные данные) | src-tauri/src/modules/account.rs | 178-206 |
| После повторного добавления аккаунта автоматически перезагрузить proxy accounts (немедленно вступает в силу во время работы) | src-tauri/src/commands/mod.rs | 21-59 |