{"record":{"id":"080c116f1d16a377","repo":"xtekky/gpt4free","slug":"no-refresh-token-080c11","errorCode":"NO_REFRESH_TOKEN","errorMessage":"No refresh token","messagePattern":"No refresh token","errorType":"exception","errorClass":"TokenManagerError","httpStatus":null,"severity":"error","filePath":"g4f/Provider/qwen/sharedTokenManager.py","lineNumber":178,"sourceCode":"            if field not in data or not isinstance(data[field], str):\n                raise ValueError(f\"Invalid credentials: missing {field}\")\n        if \"expiry_date\" not in data or not isinstance(\n            data[\"expiry_date\"], (int, float)\n        ):\n            raise ValueError(\"Invalid credentials: missing expiry_date\")\n        return data\n\n    async def performTokenRefresh(\n        self, qwen_client: IQwenOAuth2Client, force_refresh: bool\n    ):\n        lock_path = self.getLockFilePath()\n        try:\n            if self.memory_cache[\"credentials\"] is None:\n                self.reloadCredentialsFromFile()\n            qwen_client.setCredentials(self.memory_cache[\"credentials\"])\n            current_credentials = qwen_client.getCredentials()\n            if not current_credentials.get(\"refresh_token\"):\n                raise TokenManagerError(TokenError.NO_REFRESH_TOKEN, \"No refresh token\")\n            await self.acquireLock(lock_path)\n\n            self.checkAndReloadIfNeeded()\n\n            if (\n                not force_refresh\n                and self.memory_cache[\"credentials\"]\n                and self.isTokenValid(self.memory_cache[\"credentials\"])\n            ):\n                qwen_client.setCredentials(self.memory_cache[\"credentials\"])\n                return self.memory_cache[\"credentials\"]\n\n            response = await qwen_client.refreshAccessToken()\n            if not response or isErrorResponse(response):\n                raise TokenManagerError(TokenError.REFRESH_FAILED, str(response))\n            token_data = response\n            if \"access_token\" not in token_data:\n                raise TokenManagerError(","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/Provider/qwen/sharedTokenManager.py#L160-L196","documentation":"TokenManagerError NO_REFRESH_TOKEN raised at the top of SharedTokenManager.performTokenRefresh (sharedTokenManager.py:178): after loading credentials into the client, the stored credentials have no 'refresh_token', so a refresh is impossible. Unlike error 247 this fires inside the shared manager's coordinated refresh path and is typed, letting callers distinguish 'must re-auth' from generic failures.","triggerScenarios":"getValidCredentials() triggers performTokenRefresh while the loaded credentials dict lacks refresh_token — after a prior expiry wiped it, on a first run with a partially populated file, or after failed validation left None credentials reloaded from a sparse file.","commonSituations":"Post-expiry state where qwenOAuth2 reset credentials; credentials file created by an older g4f that didn't persist refresh_token; manual token extraction that copied only the access token.","solutions":["Re-run the Qwen device authorization flow to mint a full credential set","Inspect the credentials file and add/repair the refresh_token field if you have a valid one","Catch TokenManagerError with code NO_REFRESH_TOKEN in callers and route the user to re-login instead of retrying"],"exampleFix":"// before\ncreds = await manager.getValidCredentials(client)  # raises NO_REFRESH_TOKEN\n\n// after\nfrom g4f.Provider.qwen.sharedTokenManager import TokenManagerError, TokenError\ntry:\n    creds = await manager.getValidCredentials(client)\nexcept TokenManagerError as e:\n    if e.error == TokenError.NO_REFRESH_TOKEN:\n        await start_device_login()  # re-auth instead of retry\n    else:\n        raise","handlingStrategy":"validation","validationCode":"creds = manager.memory_cache.get(\"credentials\")\nif creds is None or not creds.get(\"refresh_token\"):\n    await start_qwen_device_login()  # nothing to refresh; authenticate first\ncreds = await manager.getValidCredentials(qwen_client)","typeGuard":"def has_refresh_token(creds) -> bool:\n    return isinstance(creds, dict) and isinstance(creds.get(\"refresh_token\"), str) and bool(creds[\"refresh_token\"])","tryCatchPattern":"from g4f.Provider.qwen.sharedTokenManager import TokenManagerError\ntry:\n    creds = await manager.getValidCredentials(qwen_client)\nexcept TokenManagerError as e:\n    if getattr(e, \"error\", None) is not None and \"NO_REFRESH_TOKEN\" in str(e.error):\n        await start_qwen_device_login()  # typed signal: re-auth, never retry\n    else:\n        raise","preventionTips":["Branch on the NO_REFRESH_TOKEN code — retrying is pointless without a token","Ensure the first successful login persists all fields including refresh_token","Audit the credentials file after any error that wipes credentials"],"tags":["qwen","token-manager","refresh-token","authentication"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}