Significant-Gravitas/AutoGPT · error · Error

Server did not return an access token for the Google Drive p

Error message

Server did not return an access token for the Google Drive picker.

What it means

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.

Source

Thrown at autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts:28

import {
  getCredentialsSchema,
  GooglePickerView,
  loadGoogleAPIPicker,
  loadGoogleIdentityServices,
  mapViewId,
  NormalizedPickedFile,
  normalizePickerResponse,
  scopesIncludeDrive,
} from "./helpers";
import { okData } from "@/app/api/helpers";

export async function fetchPickerAccessToken(
  credentialId: string,
): Promise<string> {
  const response = await postV1GetPickerToken("google", credentialId);
  const token = okData(response)?.access_token;
  if (!token) {
    throw new Error(
      "Server did not return an access token for the Google Drive picker.",
    );
  }
  return token;
}

/**
 * Whether a saved credential's granted scopes cover every scope the picker
 * is asking for.  Pulled out of openPicker() so the scope-gate can be
 * exercised directly — the hook flow around it needs a browser env and
 * is hard to test in isolation.  `undefined` required-scopes is treated
 * as "no scope requirement".
 */
export function hasAllRequiredScopes(
  credentialScopes: readonly string[] | null | undefined,
  requiredScopes: readonly string[] | null | undefined,
): boolean {
  if (!requiredScopes || requiredScopes.length === 0) return true;

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Delete and re-connect the Google credential in platform settings — a fresh consent flow restores the refresh token.
  2. Verify backend GOOGLE_CLIENT_ID/SECRET env vars are current (a rotated secret breaks refresh for all existing grants).
  3. Check backend logs for the token-refresh call to Google — the 200-with-no-token response body usually contains the Google error there.
  4. If the backend returns error info in the body, surface it in this error message instead of the generic string.
Defensive patterns

Strategy: type-guard

Type guard

function hasAccessToken(res: unknown): res is { access_token: string } {
  return typeof res === "object" && res !== null &&
    typeof (res as any).access_token === "string" && (res as any).access_token.length > 0;
}

Try / catch

try {
  await openPicker(credentialId);
} catch (error) {
  if (error instanceof Error && error.message.includes("did not return an access token")) {
    // prompt user to re-connect the Google credential — grant is stale
    promptReconnect("google", credentialId);
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/8098612aed958d79. Report an issue: GitHub.