xtekky/gpt4free · error · RuntimeError
No refresh token found in GCP_SERVICE_ACCOUNT.
Error message
No refresh token found in GCP_SERVICE_ACCOUNT.
What it means
Raised by AuthManager when the cached Google access token is missing or inside the TOKEN_BUFFER_TIME window and the credentials in GCP_SERVICE_ACCOUNT contain no refresh_token. The OAuth refresh flow at OAUTH_REFRESH_URL requires a refresh token to mint a new access token, so the auth manager cannot recover on its own. It means the stored credential set is incomplete, not merely expired.
Source
Thrown at g4f/Provider/needs_auth/GeminiCLI.py:397
raise RuntimeError("GCP_SERVICE_ACCOUNT environment variable not set.")
creds = json.loads(self.env["GCP_SERVICE_ACCOUNT"])
refresh_token = creds.get("refresh_token")
access_token = creds.get("access_token")
expiry_date = creds.get("expiry_date") # milliseconds since epoch
# Use original access token if still valid
if access_token and expiry_date:
expires_at = expiry_date / 1000
if expires_at - now > self.TOKEN_BUFFER_TIME:
self._access_token = access_token
self._expiry = expires_at
await self._cache_token(access_token, expiry_date)
return
# Otherwise, refresh token
if not refresh_token:
raise RuntimeError("No refresh token found in GCP_SERVICE_ACCOUNT.")
await self._refresh_and_cache_token(refresh_token)
async def _refresh_and_cache_token(self, refresh_token: str) -> None:
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"client_id": self.OAUTH_CLIENT_ID,
"client_secret": self.OAUTH_CLIENT_SECRET,
"refresh_token": refresh_token,
"grant_type": "refresh_token",
}
async with aiohttp.ClientSession() as session:
async with session.post(
self.OAUTH_REFRESH_URL, data=data, headers=headers
) as resp:
if resp.status != 200:
text = await resp.text()View on GitHub (pinned to 973504e177)
Solutions
- Re-run the GeminiCLI login flow (GeminiCLI.login / the g4f CLI auth command) to obtain a full token set, then store the returned JSON (access_token, refresh_token, expiry_date) in GCP_SERVICE_ACCOUNT
- Verify the stored credential actually contains a refresh token: python -c "import os,json;print(bool(json.loads(os.environ['GCP_SERVICE_ACCOUNT']).get('refresh_token')))"
- If the refresh token was revoked (Google Account > Security > Third-party access), revoke the app there and re-authorize
- Make sure GCP_SERVICE_ACCOUNT is valid JSON and not truncated by shell quoting or newlines when exported
Example fix
// before
export GCP_SERVICE_ACCOUNT='{"access_token":"ya29...","expiry_date":1750000000000}'
// after
export GCP_SERVICE_ACCOUNT='{"access_token":"ya29...","refresh_token":"1//0g...","expiry_date":1750000000000}' Defensive patterns
Strategy: validation
Validate before calling
import json, os
def has_refresh_token() -> bool:
raw = os.environ.get("GCP_SERVICE_ACCOUNT", "")
if not raw:
return False
try:
creds = json.loads(raw)
except json.JSONDecodeError:
return False
return bool(creds.get("refresh_token"))
if not has_refresh_token():
raise SystemExit("GCP_SERVICE_ACCOUNT lacks refresh_token; run GeminiCLI.login first") Try / catch
try:
result = await GeminiCLI.create_async_generator(model, messages)
except RuntimeError as e:
if "No refresh token found" in str(e):
await GeminiCLI.login() # then retry once Prevention
- Always obtain GCP_SERVICE_ACCOUNT via the login flow, never hand-assemble it
- Validate the JSON parses and contains refresh_token before starting the app
- Keep the KV token cache warm so refresh is rarely needed
When it happens
Trigger: Calling GeminiCLI after the previously cached access token's expiry (expiry_date/1000 minus now) is below TOKEN_BUFFER_TIME, while the parsed GCP_SERVICE_ACCOUNT JSON has access_token/expiry_date but no non-empty refresh_token field.
Common situations: User pasted only the access_token portion of a token dump into GCP_SERVICE_ACCOUNT; token JSON produced by an older or external login tool that omits refresh_token; refresh token revoked or stripped when the Google OAuth consent was removed; KV token cache cleared so refresh is attempted for the first time.
Related errors
- Token refresh failed: {text}
- No access_token in refresh response.
- TokenError.FILE_ACCESS_ERROR
- OAuth error: {OAuthCallbackHandler.callback_error}
- Failed to read OAuth credentials from {path}: {e}
AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14).
Data as JSON: /api/errors/92fc31710accaa8d.
Report an issue: GitHub.