{"record":{"id":"c8a78e713f69d829","repo":"yikart/AiToEarn","slug":"failed-to-refresh-access-token","errorCode":null,"errorMessage":"Failed to refresh access token","messagePattern":"Failed to refresh access token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/google/google.service.ts","lineNumber":765,"sourceCode":"\n      // const expires = 30 * 24 * 60 * 60\n      console.log(\"accessTokenInfo:---\", accessTokenInfo);\n      // console.log(\"expires:---\", accessTokenInfo.expires_in);\n      this.redisService.setKey(\n        `google:accessToken:${userId}`,\n        accessTokenInfo,\n        accessTokenInfo.expires_in\n      );\n\n      // return result.data;\n      return systemToken;\n\n\n      // 返回新的 access token 和其他信息\n      // return response.data;  // 包含新的 access_token、expires_in、token_type 等信息\n    } catch (err) {\n      console.log('Error while refreshing access token', err);\n      throw new Error('Failed to refresh access token');\n    }\n  }\n\n  /**\n   * 查询用户已授权权限列表\n   * @returns\n   */\n  async getAccountScopes(accessToken: string) {\n    try {\n      // 初始化 OAuth2 客户端\n      // const oAuth2Client = new google.auth.OAuth2();\n      this.oauth2Client.setCredentials({\n        access_token: accessToken,\n      });\n\n      // 通过访问 token 查询 token 信息\n      const tokenInfo = await google.oauth2('v2').tokeninfo({\n        access_token: accessToken,","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/google/google.service.ts#L747-L783","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n} catch (err) {\n  console.log('Error while refreshing access token', err);\n  throw new Error('Failed to refresh access token');\n}\n// after\n} catch (err) {\n  const detail = err?.response?.data?.error || err?.message;\n  throw new Error(`Failed to refresh access token: ${detail}`, { cause: err });\n}","handlingStrategy":"retry","validationCode":"if (!refreshToken) {\n  throw new Error('No refresh token stored for this account; re-authorization required');\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await googleService.getUserAccessToken(account);\n} catch (err) {\n  if (err.message.includes('Failed to refresh access token')) {\n    await markAccountNeedsReauth(account.id); // invalid_grant: token dead\n    throw new UnauthorizedException('Please reconnect your Google account');\n  }\n  throw err; // transient: let caller retry\n}","preventionTips":["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"],"tags":["google","oauth","token-refresh","network"],"backgroundTag":"token-refresh-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}