{"record":{"id":"8098612aed958d79","repo":"Significant-Gravitas/AutoGPT","slug":"server-did-not-return-an-access-token-for-the-goog","errorCode":null,"errorMessage":"Server did not return an access token for the Google Drive picker.","messagePattern":"Server did not return an access token for the Google Drive picker\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts","lineNumber":28,"sourceCode":"import {\n  getCredentialsSchema,\n  GooglePickerView,\n  loadGoogleAPIPicker,\n  loadGoogleIdentityServices,\n  mapViewId,\n  NormalizedPickedFile,\n  normalizePickerResponse,\n  scopesIncludeDrive,\n} from \"./helpers\";\nimport { okData } from \"@/app/api/helpers\";\n\nexport async function fetchPickerAccessToken(\n  credentialId: string,\n): Promise<string> {\n  const response = await postV1GetPickerToken(\"google\", credentialId);\n  const token = okData(response)?.access_token;\n  if (!token) {\n    throw new Error(\n      \"Server did not return an access token for the Google Drive picker.\",\n    );\n  }\n  return token;\n}\n\n/**\n * Whether a saved credential's granted scopes cover every scope the picker\n * is asking for.  Pulled out of openPicker() so the scope-gate can be\n * exercised directly — the hook flow around it needs a browser env and\n * is hard to test in isolation.  `undefined` required-scopes is treated\n * as \"no scope requirement\".\n */\nexport function hasAllRequiredScopes(\n  credentialScopes: readonly string[] | null | undefined,\n  requiredScopes: readonly string[] | null | undefined,\n): boolean {\n  if (!requiredScopes || requiredScopes.length === 0) return true;","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts#L10-L46","documentation":"Thrown by fetchPickerAccessToken when postV1GetPickerToken('google', credentialId) succeeds (2xx) but the response body contains no access_token (okData(response)?.access_token is falsy). The token is required to initialize the Google Drive picker, so its absence aborts picker opening. Root causes split into: backend didn't get a token from Google (expired/revoked OAuth grant) but still returned 200, or the credential was disconnected.","triggerScenarios":"Calling the picker with a Google credential whose refresh token expired/revoked (Google revoked offline access, user removed the app from their Google account), or backend's Google OAuth credentials misconfigured so token refresh fails silently, or a backend bug returning 200 with an error body that lacks access_token.","commonSituations":"User revoked platform access in their Google account settings then tries to attach a Drive file; Google OAuth app in testing mode with expired grants (>7 days); stale credential rows after backend OAuth config changed; refresh-token never persisted at initial consent (prompt=consent not used).","solutions":["Delete and re-connect the Google credential in platform settings — a fresh consent flow restores the refresh token.","Verify backend GOOGLE_CLIENT_ID/SECRET env vars are current (a rotated secret breaks refresh for all existing grants).","Check backend logs for the token-refresh call to Google — the 200-with-no-token response body usually contains the Google error there.","If the backend returns error info in the body, surface it in this error message instead of the generic string."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasAccessToken(res: unknown): res is { access_token: string } {\n  return typeof res === \"object\" && res !== null &&\n    typeof (res as any).access_token === \"string\" && (res as any).access_token.length > 0;\n}","tryCatchPattern":"try {\n  await openPicker(credentialId);\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"did not return an access token\")) {\n    // prompt user to re-connect the Google credential — grant is stale\n    promptReconnect(\"google\", credentialId);\n  }\n}","preventionTips":["Type-guard the token response (non-empty access_token string) before initializing the picker.","Verify credential granted scopes with scopesIncludeDrive before even requesting the picker token.","Treat 200-with-no-token as 'credential disconnected' and offer a reconnect flow immediately."],"tags":["google-drive","oauth","credentials","picker","frontend"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}