mastra-ai/mastra · error

Google service account token request failed (${response.stat

Error message

Google service account token request failed (${response.status}): ${await response.text()}

What it means

Thrown when the HTTPS request to Google's OAuth2 token endpoint (https://oauth2.googleapis.com/token) returns a non-OK status. The response status and body are included, and the body typically contains Google's error description (e.g. invalid_grant, invalid_scope, invalid_client). This means the client id, key, scopes, or clock are wrong — the token was never issued.

Source

Thrown at auth/google/src/rbac-provider.ts:238

      throw new Error(
        `Google service account private key signing failed (${(err as Error).message}). ` +
          `Key has BEGIN marker: ${hasBegin}, END marker: ${hasEnd}. ` +
          `Ensure your .env value contains the raw PEM with \\n for newlines, without extra surrounding quotes or commas.`,
      );
    }

    const response = await fetch(OAUTH_TOKEN_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        assertion: `${unsigned}.${signature}`,
      }),
      signal: AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS),
    });

    if (!response.ok) {
      throw new Error(`Google service account token request failed (${response.status}): ${await response.text()}`);
    }

    const json = (await response.json()) as { access_token: string; expires_in: number };
    this.accessToken = json.access_token;
    this.tokenExpiresAt = Date.now() + json.expires_in * 1000;
    return json.access_token;
  }

  private base64Url(value: string): string {
    return Buffer.from(value).toString('base64url');
  }

  private normalizePrivateKey(key: string): string {
    let out = key.trim();

    for (let i = 0; i < 5; i++) {
      const before = out;
      if (out.endsWith(',')) out = out.slice(0, -1).trim();

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the included response body — Google's error (e.g. 'invalid_grant: Invalid JWT Signature') pinpoints the cause
  2. Verify the service account client_email and private_key are from the same JSON key file and the key is still active in Google Cloud Console
  3. Synchronize the machine clock (NTP) — JWT issued_at/expired_at skew causes invalid_grant
  4. Confirm requested scopes are valid and the service account is enabled and not rate-limited
Defensive patterns

Strategy: retry

Validate before calling

// Validate inputs before calling
if (!clientEmail || !privateKey || !clientEmail.endsWith('.iam.gserviceaccount.com')) {
  throw new Error('Invalid Google service account credentials');
}
// Check clock skew
const skew = Math.abs(Date.now() - (await getServerTimeUtc()));
if (skew > 60_000) throw new Error('System clock skewed by ' + skew + 'ms');

Try / catch

try {
  const token = await provider.getToken();
} catch (err) {
  const msg = err instanceof Error ? err.message : '';
  if (msg.includes('invalid_grant')) {
    // key revoked/expired or clock skew — do NOT retry with same creds
    console.error('Check service account key validity and system clock');
  } else if (msg.includes('status: 5') || msg.includes('status: 429')) {
    await new Promise(r => setTimeout(r, 1000)); // transient — safe to retry
    return provider.getToken();
  }
  throw err;
}

Prevention

When it happens

Trigger: getServiceAccountToken() performs a fetch of the signed JWT assertion (grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer) to Google's token endpoint; any 4xx/5xx response (most commonly 400 invalid_grant) triggers this error.

Common situations: Expired or revoked service account key; system clock skew greater than a few minutes; wrong client_email paired with the private key; the service account being disabled or lacking the requested scopes; network proxies returning error bodies.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/6f3e8a5db3d07876. Report an issue: GitHub.