{"record":{"id":"3a4114159f27cdc4","repo":"xtekky/gpt4free","slug":"no-access-token-in-refresh-response","errorCode":null,"errorMessage":"No access_token in refresh response.","messagePattern":"No access_token in refresh response\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"g4f/Provider/needs_auth/Antigravity.py","lineNumber":463,"sourceCode":"            \"client_id\": self.OAUTH_CLIENT_ID,\n            \"client_secret\": self.OAUTH_CLIENT_SECRET,\n            \"refresh_token\": refresh_token,\n            \"grant_type\": \"refresh_token\",\n        }\n\n        async with aiohttp.ClientSession() as session:\n            async with session.post(\n                self.OAUTH_REFRESH_URL, data=data, headers=headers\n            ) as resp:\n                if resp.status != 200:\n                    text = await resp.text()\n                    raise RuntimeError(f\"Token refresh failed: {text}\")\n                resp_data = await resp.json()\n                access_token = resp_data.get(\"access_token\")\n                expires_in = resp_data.get(\"expires_in\", 3600)  # seconds\n\n                if not access_token:\n                    raise RuntimeError(\"No access_token in refresh response.\")\n\n                self._access_token = access_token\n                self._expiry = time.time() + expires_in\n\n                expiry_date_ms = int(self._expiry * 1000)  # milliseconds\n                await self._cache_token(access_token, expiry_date_ms)\n\n    async def _cache_token(self, access_token: str, expiry_date: int) -> None:\n        \"\"\"Cache token in memory.\"\"\"\n        token_data = {\n            \"access_token\": access_token,\n            \"expiry_date\": expiry_date,\n            \"cached_at\": int(time.time() * 1000),  # ms\n        }\n        self._token_cache[self.KV_TOKEN_KEY] = token_data\n\n    async def _get_cached_token(self) -> Optional[Dict[str, Any]]:\n        \"\"\"Return in-memory cached token if present and still valid.\"\"\"","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/Provider/needs_auth/Antigravity.py#L445-L481","documentation":"Thrown when the OAuth refresh endpoint returns HTTP 200 but the JSON body has no 'access_token' field. A 200 without an access token is unusual for Google's token endpoint and typically means the response is not the expected OAuth payload (proxy interception, HTML error page parsed as JSON, or an API contract change).","triggerScenarios":"session.post(OAUTH_REFRESH_URL, ...) returns 200, resp.json() succeeds, but resp_data.get('access_token') is empty/None. Happens with captive portals or corporate proxies returning 200 HTML pages, or a misconfigured OAUTH_REFRESH_URL pointing at the wrong endpoint.","commonSituations":"Corporate MITM proxy returns a 200 login page for googleapis.com; the endpoint constant was patched/overridden; Google returned an unexpected payload shape.","solutions":["Log the full refresh response body to see what actually came back instead of an OAuth token JSON.","Check for HTTP(S) proxy interference (HTTPS_PROXY env, captive portal) and bypass or trust it properly.","Delete the cached credentials and re-authenticate from scratch.","If OAUTH_REFRESH_URL was overridden in a subclass, restore the official https://oauth2.googleapis.com/token endpoint."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    ...\nexcept RuntimeError as e:\n    if \"No access_token in refresh response\" in str(e):\n        # log raw response via debug logging; suspect proxy; re-login\n        await antigravity.login()","preventionTips":["Keep googleapis.com out of MITM/proxy rewriting paths","Pin provider version so OAUTH_REFRESH_URL matches Google's contract","Log refresh responses at debug level in production to catch shape changes early"],"tags":["oauth","authentication","proxy","antigravity"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}