{"record":{"id":"32f06c6ec11a80fb","repo":"meteor/meteor","slug":"e-reason","errorCode":null,"errorMessage":"${e.reason}","messagePattern":"\\$\\{e\\.reason\\}","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"packages/google-oauth/google_server.js","lineNumber":206,"sourceCode":"  callback && callback(undefined, response);\n  return response;\n};\n\nconst getScopes = async (accessToken, callback) => {\n  const content = new URLSearchParams({ access_token: accessToken });\n  let response;\n  try {\n    const request = await OAuth._fetch(\n      `https://www.googleapis.com/oauth2/v1/tokeninfo?${content.toString()}`,\n      'GET',\n      {\n        headers: { Accept: 'application/json' },\n      }\n    );\n    response = await request.json();\n  } catch (e) {\n    callback && callback(e);\n    throw new Meteor.Error(e.reason);\n  }\n  callback && callback(undefined, response.scope.split(' '));\n  return response.scope.split(' ');\n};\n\nGoogle.retrieveCredential = (credentialToken, credentialSecret) =>\n  OAuth.retrieveCredential(credentialToken, credentialSecret);\n","sourceCodeStart":188,"sourceCodeEnd":214,"githubUrl":"https://github.com/meteor/meteor/blob/5076d2f818d3cac01d0cf8312fa5b2332076a4fb/packages/google-oauth/google_server.js#L188-L214","documentation":"Thrown inside getScopes() during the Google OAuth handshake when the HTTP request to Google's tokeninfo endpoint (https://www.googleapis.com/oauth2/v1/tokeninfo) fails to complete. The caught exception e comes from OAuth._fetch or request.json(); its .reason is used as the Meteor.Error reason. This aborts Google sign-in because the scopes list cannot be retrieved.","triggerScenarios":"The access token sent to getServiceDataFromTokens -> getScopes is expired, revoked, or malformed so googleapis.com returns an error body or non-200; the outbound network request to googleapis.com fails (DNS, proxy, timeout); the response body is not valid JSON so request.json() throws.","commonSituations":"Expired or revoked access token reaching the server login handler; corporate proxy/firewall blocking googleapis.com; clock skew between server and Google; a malformed serverAuthCode exchanged for tokens that the tokeninfo endpoint then rejects.","solutions":["Verify the accessToken reaching the server is fresh and not expired before it is sent to tokeninfo.","Confirm the server has outbound HTTPS access to https://www.googleapis.com.","Inspect the underlying error (note e.reason may be undefined for raw fetch errors; consider falling back to e.message).","Re-run the client OAuth flow to obtain new tokens and complete the handshake again."],"exampleFix":"// before\n  } catch (e) {\n    callback && callback(e);\n    throw new Meteor.Error(e.reason);\n  }\n\n// after\n  } catch (e) {\n    const reason = e.reason || e.message || 'Failed to fetch Google token info';\n    callback && callback(e);\n    throw new Meteor.Error(reason);\n  }","handlingStrategy":"try-catch","validationCode":"// Before triggering the login handler, sanity-check the token and egress\nimport { fetch } from 'meteor/fetch';\nasync function tokenLooksValid(accessToken) {\n  if (!accessToken || typeof accessToken !== 'string') return false;\n  try {\n    const res = await fetch('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + accessToken);\n    return res.ok;\n  } catch {\n    return false; // network problem — do not proceed\n  }\n}","typeGuard":null,"tryCatchPattern":"// In the registerLoginHandler / caller, wrap the Google handshake\ntry {\n  result = await getServiceDataFromTokens(tokens);\n} catch (err) {\n  // err.message already prefixed with 'Failed to complete OAuth handshake with Google.'\n  throw new Meteor.Error('google-handshake-failed', err.message);\n}","preventionTips":["Refresh Google tokens before they expire rather than relying on the server to detect expiry.","Ensure server egress to https://www.googleapis.com is allowed by firewall/proxy.","Log err.message (not err.reason) since raw fetch errors often lack a reason field."],"tags":["oauth","google","network","authentication"],"backgroundTag":null,"analyzedSha":"5076d2f818d3cac01d0cf8312fa5b2332076a4fb","analyzedAt":"2026-08-13T03:27:40.142Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}