{"record":{"id":"b97f24f455d294d6","repo":"Aider-AI/aider","slug":"github-copilot-api-request-failed-status-res-st","errorCode":null,"errorMessage":"GitHub Copilot API request failed (Status: {res.status_code})\nURL: {url}\nHeaders: {json.dumps(safe_headers, indent=2)}\nJSON: {res.text}","messagePattern":"GitHub Copilot API request failed \\(Status: (.+?)\\)\nURL: (.+?)\nHeaders: (.+?)\nJSON: (.+?)","errorType":"exception","errorClass":"GitHubCopilotTokenError","httpStatus":null,"severity":"error","filePath":"aider/models.py","lineNumber":971,"sourceCode":"\n            github_token = os.environ[\"GITHUB_COPILOT_TOKEN\"]\n            if not github_token.strip():\n                raise KeyError(\"GITHUB_COPILOT_TOKEN environment variable is empty\")\n\n            headers = {\n                \"Authorization\": f\"Bearer {os.environ['GITHUB_COPILOT_TOKEN']}\",\n                \"Editor-Version\": extra_headers[\"Editor-Version\"],\n                \"Copilot-Integration-Id\": extra_headers[\"Copilot-Integration-Id\"],\n                \"Content-Type\": \"application/json\",\n            }\n\n            url = \"https://api.github.com/copilot_internal/v2/token\"\n            res = requests.get(url, headers=headers)\n            if res.status_code != 200:\n                safe_headers = {k: v for k, v in headers.items() if k != \"Authorization\"}\n                token_preview = github_token[:5] + \"...\" if len(github_token) >= 5 else github_token\n                safe_headers[\"Authorization\"] = f\"Bearer {token_preview}\"\n                raise GitHubCopilotTokenError(\n                    f\"GitHub Copilot API request failed (Status: {res.status_code})\\n\"\n                    f\"URL: {url}\\n\"\n                    f\"Headers: {json.dumps(safe_headers, indent=2)}\\n\"\n                    f\"JSON: {res.text}\"\n                )\n\n            response_data = res.json()\n            token = response_data.get(\"token\")\n            if not token:\n                raise GitHubCopilotTokenError(\"Response missing 'token' field\")\n\n            os.environ[openai_api_key] = token\n\n    def send_completion(self, messages, functions, stream, temperature=None):\n        if os.environ.get(\"AIDER_SANITY_CHECK_TURNS\"):\n            sanity_check_messages(messages)\n\n        if self.is_deepseek_r1():","sourceCodeStart":953,"sourceCodeEnd":989,"githubUrl":"https://github.com/Aider-AI/aider/blob/5dc9490bb35f9729ef2c95d00a19ccd30c26339c/aider/models.py#L953-L989","documentation":"The GitHub Copilot token-exchange GET to https://api.github.com/copilot_internal/v2/token returned a non-200 status, and aider raises its locally-defined GitHubCopilotTokenError with status code, URL, safe headers (Authorization redacted to a 5-char preview), and the raw response body. This is the server rejecting the exchange: 401 for a bad/expired GitHub token, 403 for no Copilot subscription, 404/429 for endpoint or rate issues. The response text embedded in the message tells you which.","triggerScenarios":"Any non-200 from the token endpoint during a Copilot model call: expired or revoked gho_ GitHub token (401), account without an active Copilot subscription (403), rate limiting on the internal endpoint (429), or GitHub API incidents. Only fires when the cached Copilot token is expired, so symptoms can start mid-session.","commonSituations":"Long-lived sessions where the GitHub OAuth token quietly expired or was revoked by a password change/re-auth elsewhere; using Copilot models on an account whose subscription lapsed; heavy automation hitting the internal token endpoint and being throttled.","solutions":["Read the embedded JSON body in the error message: 401 'Bad credentials' means refresh your GITHUB_COPILOT_TOKEN; 403 suggests the account lacks a Copilot subscription.","Re-run the auth flow that produced GITHUB_COPILOT_TOKEN and re-export a fresh token, then retry.","Confirm the account has an active GitHub Copilot entitlement; without it the internal endpoint is forbidden.","For 429s, back off and retry later — the internal token endpoint is rate-limited."],"exampleFix":"# before: stale token exported weeks ago\nexport GITHUB_COPILOT_TOKEN=\"gho_old...\"  # later: GitHubCopilotTokenError: Status 401\n\n# after: refresh and verify\nexport GITHUB_COPILOT_TOKEN=\"$(gh auth token)\"  # or re-run device-code flow\npython -c \"import os,requests; r=requests.get('https://api.github.com/copilot_internal/v2/token', headers={'Authorization': f'Bearer {os.environ[\"GITHUB_COPILOT_TOKEN\"]}', 'Editor-Version': 'aider/1', 'Copilot-Integration-Id': 'vscode-chat'}); print(r.status_code)\"  # expect 200","handlingStrategy":"retry","validationCode":"import os, requests\n\ndef copilot_token_exchange_ok():\n    \"\"\"Probe the token exchange endpoint; True = credentials healthy.\"\"\"\n    tok = os.environ.get(\"GITHUB_COPILOT_TOKEN\", \"\")\n    if not tok.strip():\n        return False\n    h = {\n        \"Authorization\": f\"Bearer {tok}\",\n        \"Editor-Version\": \"aider/probe\",\n        \"Copilot-Integration-Id\": \"vscode-chat\",\n    }\n    try:\n        return requests.get(\n            \"https://api.github.com/copilot_internal/v2/token\", headers=h, timeout=10\n        ).status_code == 200\n    except requests.RequestException:\n        return False","typeGuard":null,"tryCatchPattern":"import time\nfor attempt in range(3):\n    try:\n        out = model.send_completion(messages, None, False)\n        break\n    except Exception as e:\n        msg = str(e)\n        if \"401\" in msg or \"403\" in msg:\n            raise SystemExit(\"Copilot token rejected/expired — re-authenticate.\")\n        if \"429\" in msg and attempt < 2:\n            time.sleep(2 ** attempt)  # rate limited: back off and retry\n            continue\n        raise","preventionTips":["Treat 401 as a hard stop: refresh the GitHub token instead of retrying.","Add exponential backoff around the token exchange for 429/5xx responses.","Probe the endpoint once at startup (cheap GET) so bad credentials fail fast with a clear message."],"tags":["network","http","github-copilot","authentication","token-expiry","aider"],"backgroundTag":null,"analyzedSha":"5dc9490bb35f9729ef2c95d00a19ccd30c26339c","analyzedAt":"2026-08-15T05:40:10.498Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}