odysseus-dev/odysseus · error · HTTPException
GitHub device-code request failed (HTTP {status})
Error message
GitHub device-code request failed (HTTP {status}) What it means
Raised (HTTP 502) by the Copilot device-flow login start helper when copilot.request_device_code(host) fails with an httpx.HTTPStatusError — i.e. GitHub's (or GitHub Enterprise Server's) device-code endpoint returned a non-2xx HTTP status. The 502 signals the failure is upstream at the OAuth provider, not in this app; the status code from the failed response (or 'unknown' if the exception carries no response) is embedded in the message. Host selection honors an enterprise_url form field normalized via copilot.normalize_domain.
Source
Thrown at routes/copilot_routes.py:111
# Best-effort: refresh the model cache so the new endpoint shows up.
try:
from routes.model_routes import _invalidate_models_cache
_invalidate_models_cache()
except Exception:
pass
return result
def _start_device_flow(request: Request, form) -> DeviceFlowStart:
host = copilot.GITHUB_HOST
ent = str(form.get("enterprise_url") or "").strip()
if ent:
host = copilot.normalize_domain(ent)
try:
data = copilot.request_device_code(host)
except httpx.HTTPStatusError as e:
status = e.response.status_code if e.response is not None else "unknown"
raise HTTPException(502, f"GitHub device-code request failed (HTTP {status})")
except Exception as e:
raise HTTPException(502, f"GitHub device-code request failed: {e}")
device_code = data.get("device_code")
if not device_code:
raise HTTPException(502, "GitHub did not return a device code")
# verification_uri_complete embeds the user code, so the browser tab we
# open lands the user straight on GitHub's "Authorize" screen with the
# code pre-filled — one click, no manual code entry.
return DeviceFlowStart(
pending={
"device_code": device_code,
"host": host,
"enterprise_url": ent,
"owner": get_current_user(request) or None,
},
response={View on GitHub (pinned to f9235ebbf1)
Solutions
- If enterprise_url was entered, verify it is the correct GitHub Enterprise Server domain and that device-flow OAuth is enabled there; otherwise clear it to use github.com.
- Wait and retry if the embedded status is 429 (rate limited) — repeated login restarts compound the limit.
- If status is 401/403/404 on plain github.com, check the app's Copilot OAuth client configuration (client_id) in the copilot module.
- Check https://www.githubstatus.com for 5xx-side outages when the status is 500+.
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: the device endpoint should respond before starting login
async function githubReachable(host = 'github.com') {
const res = await fetch(`https://${host}/login/device/code`, { method: 'HEAD' }).catch(() => null);
return res !== null;
} Try / catch
try { start = await post('/copilot/device/start', form); } catch (e) { if (e.status === 502 && /HTTP (429|5\d\d)/.test(e.message)) { await backoff(); return retryStart(); } if (/HTTP 40[13]/.test(e.message)) { showHelp('Check enterprise_url / OAuth client config'); } throw e; } Prevention
- Validate enterprise_url format before submitting and let users clear it to fall back to github.com.
- Rate-limit login-start attempts client-side (no auto-retry loops) to avoid 429s.
When it happens
Trigger: Starting Copilot device-code login while github.com/login/device/code (or the GHES equivalent at the enterprise domain) returns an error status: 401/403 for a bad or expired OAuth client_id, 404 when the enterprise URL is wrong or the instance does not enable device flow, 429 rate limiting, 5xx outages.
Common situations: Misconfigured enterprise_url (points at a GHES host where the device-flow app is not registered); GitHub rate-limits device-code requests during repeated login attempts; GitHub or GHES outage; the app's Copilot OAuth client credentials were revoked.
Related errors
- GitHub did not return a device code
- GitHub device-code request failed: {e}
- Login succeeded but provisioning failed: {e}
- Request failed (HTTP ${response.status})
- Unknown device-flow provider: ${provider}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/8bce850a4a745758.
Report an issue: GitHub.