yikart/AiToEarn · error · Error
Failed to refresh access token
Error message
Failed to refresh access token
What it means
refreshAccessToken exchanges a Google refresh token for a new access token via the Google OAuth endpoint. Any failure in that HTTP call (invalid grant, network error, expired/revoked refresh token, bad client credentials) is caught, logged, and rethrown as a generic Error('Failed to refresh access token'), discarding the original error details from the caller.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/google/google.service.ts:765
// const expires = 30 * 24 * 60 * 60
console.log("accessTokenInfo:---", accessTokenInfo);
// console.log("expires:---", accessTokenInfo.expires_in);
this.redisService.setKey(
`google:accessToken:${userId}`,
accessTokenInfo,
accessTokenInfo.expires_in
);
// return result.data;
return systemToken;
// 返回新的 access token 和其他信息
// return response.data; // 包含新的 access_token、expires_in、token_type 等信息
} catch (err) {
console.log('Error while refreshing access token', err);
throw new Error('Failed to refresh access token');
}
}
/**
* 查询用户已授权权限列表
* @returns
*/
async getAccountScopes(accessToken: string) {
try {
// 初始化 OAuth2 客户端
// const oAuth2Client = new google.auth.OAuth2();
this.oauth2Client.setCredentials({
access_token: accessToken,
});
// 通过访问 token 查询 token 信息
const tokenInfo = await google.oauth2('v2').tokeninfo({
access_token: accessToken,View on GitHub (pinned to d3aa8bea5b)
Solutions
- Uncomment/inspect the real err — console.log already prints it; check for 'invalid_grant' meaning the refresh token must be re-obtained by re-authenticating the user
- Confirm GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET match the OAuth client that issued the refresh token
- If refresh token is revoked/expired, mark the account as needing re-authorization and prompt the user to reconnect
- Verify server outbound network access to oauth2.googleapis.com
- Include err.response?.data in the thrown message for diagnosability
Example fix
// before
} catch (err) {
console.log('Error while refreshing access token', err);
throw new Error('Failed to refresh access token');
}
// after
} catch (err) {
const detail = err?.response?.data?.error || err?.message;
throw new Error(`Failed to refresh access token: ${detail}`, { cause: err });
} Defensive patterns
Strategy: retry
Validate before calling
if (!refreshToken) {
throw new Error('No refresh token stored for this account; re-authorization required');
} Try / catch
try {
return await googleService.getUserAccessToken(account);
} catch (err) {
if (err.message.includes('Failed to refresh access token')) {
await markAccountNeedsReauth(account.id); // invalid_grant: token dead
throw new UnauthorizedException('Please reconnect your Google account');
}
throw err; // transient: let caller retry
} Prevention
- Detect invalid_grant and force re-auth instead of retrying forever
- Keep GOOGLE_CLIENT_ID/SECRET stable — rotating them invalidates refresh flows
- Re-prompt users in Google testing mode before the 7-day token expiry
- Confirm server egress to oauth2.googleapis.com
When it happens
Trigger: Calling refreshAccessToken (directly or via getUserAccessToken) when the POST to https://oauth2.googleapis.com/token fails: Google returns 400 invalid_grant (refresh token expired/revoked), 401 invalid_client, network timeout, or the response lacks access_token.
Common situations: User revoked app access in Google account settings (invalid_grant); refresh token older than 7 days for apps in testing mode; GOOGLE_CLIENT_SECRET env var changed or missing; server clock skew causing token issues; sandbox without network access to Google.
Related errors
- Failed to refresh access token
- Invalid Google token
- Google login failed: ${error.message}
- Failed to get user permissions
- Failed to fetch user info
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/c8a78e713f69d829.
Report an issue: GitHub.