{"record":{"id":"858827974ca63919","repo":"yikart/AiToEarn","slug":"failed-to-get-user-permissions","errorCode":null,"errorMessage":"Failed to get user permissions","messagePattern":"Failed to get user permissions","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/google/google.service.ts","lineNumber":802,"sourceCode":"      });\n\n      console.log('Token Info:', tokenInfo.data);\n\n      // 查询用户的基本信息\n      const userInfo = await google.oauth2('v2').userinfo.get({\n        auth: this.oauth2Client,\n      });\n\n      console.log('User Info:', userInfo.data);\n\n      // 返回用户的权限和信息\n      return {\n        tokenInfo: tokenInfo.data,\n        userInfo: userInfo.data,\n      };\n    } catch (error) {\n      console.error('Error getting user permissions:', error);\n      throw new Error('Failed to get user permissions');\n    }\n  }\n\n  /**\n   * 获取已授权的用户信息\n   * @param data\n   */\n  async getUserInfo(accessToken: string, token) {\n    try {\n      const response = await axios.get('https://www.googleapis.com/oauth2/v3/userinfo', {\n        headers: {\n          Authorization: `Bearer ${accessToken}`,\n        },\n      });\n\n      // 返回用户信息\n      return response.data;\n    } catch (err) {","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/google/google.service.ts#L784-L820","documentation":"getAccountScopes fetches the user's granted OAuth scopes plus token/user info from Google. If any of those HTTP calls fail (invalid access token, expired token, network error), the whole method is wrapped and rethrown as Error('Failed to get user permissions'). It's a generic wrapper hiding which of the underlying requests failed.","triggerScenarios":"Calling getAccountScopes with an access token that Google rejects (400/401 on tokeninfo or userinfo endpoints), or when the network request to Google fails entirely.","commonSituations":"Access token already expired and refresh flow was not run first; token revoked by user; calling before getUserAccessToken completed; offline/blocked network to googleapis.com.","solutions":["Ensure a fresh access token is obtained (refreshAccessToken) before calling getAccountScopes","Check the console.error output for which request (tokenInfo vs userInfo) failed and its status","If the access token is expired/invalid, trigger the re-auth/refresh flow for that account","Verify outbound connectivity to googleapis.com from the server","Catch this error upstream and return 401 so the client knows to re-authorize"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if (!accessToken) {\n  throw new Error('Access token required before querying Google scopes');\n}","typeGuard":"function isTokenInfo(t: unknown): t is { access_token: string; expiry?: string } {\n  return !!t && typeof t === 'object' && 'access_token' in t;\n}","tryCatchPattern":"try {\n  return await googleService.getAccountScopes(accessToken);\n} catch (err) {\n  logger.warn('Scope lookup failed, treating as minimal scopes', err);\n  return { tokenInfo: null, userInfo: null, scopes: [] }; // fallback\n}","preventionTips":["Always refresh the access token before querying scopes","Verify the account is connected before calling scope endpoints","Catch and degrade gracefully — scope info is usually non-critical","Check outbound connectivity to googleapis.com in health checks"],"tags":["google","oauth","scopes","api-call"],"backgroundTag":"google-api-request-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}