nikivdev/code · error
device auth poll failed: HTTP {}
Error message
device auth poll failed: HTTP {} What it means
During the device-auth login loop, each poll of the token endpoint must return 2xx. A non-2xx poll response aborts the whole login with this error. Note that OAuth-style 'slow_down'/'authorization_pending' hints are expected as 200-with-status-body in this implementation; an HTTP-level failure here means something is wrong with the request or the service.
Source
Thrown at src/auth.rs:83
open_in_browser(&payload.verification_url);
let expires_at = Instant::now() + Duration::from_secs(payload.expires_in);
let poll_url = format!("{}/api/auth/cli/poll", api_url);
println!("Waiting for approval...");
while Instant::now() < expires_at {
sleep(Duration::from_secs(payload.interval.max(1)));
let poll_response = client
.post(&poll_url)
.json(&serde_json::json!({"device_code": payload.device_code}))
.send()
.context("failed to poll device auth")?;
if !poll_response.status().is_success() {
bail!("device auth poll failed: HTTP {}", poll_response.status());
}
let poll: DevicePollResponse = poll_response
.json()
.context("failed to parse device auth poll response")?;
match poll.status.as_str() {
"approved" => {
let token = poll
.token
.ok_or_else(|| anyhow!("device auth approved without token"))?;
env::save_ai_auth_token(token, Some(api_url.clone()))?;
println!("✓ Auth complete. You're ready to use Flow AI.");
return Ok(());
}
"pending" => continue,
"expired" => bail!("device code expired. Run `f auth` again."),
"invalid" => bail!("device code invalid. Run `f auth` again."),View on GitHub (pinned to a747e741ae)
Solutions
- Check the status code (429 → back off and slow the poll interval; 4xx → re-run 'f auth' for a fresh device code; 5xx → retry after a delay)
- Increase the poll interval to respect rate limits before retrying
- Re-run the login to obtain a new device code if the current one is rejected
- Verify API base URL / endpoint configuration matches the auth server
Example fix
// before
if !poll_response.status().is_success() {
bail!("device auth poll failed: HTTP {}", poll_response.status());
}
// after
if poll_response.status() == StatusCode::TOO_MANY_REQUESTS {
interval = Duration::from_secs(interval.as_secs() * 2);
continue;
}
if !poll_response.status().is_success() {
bail!("device auth poll failed: HTTP {}", poll_response.status());
} Defensive patterns
Strategy: retry
Validate before calling
// Poll with exponential backoff to avoid 429s
let mut interval = Duration::from_secs(5);
loop {
std::thread::sleep(interval);
interval = (interval * 2).min(Duration::from_secs(30));
// ... send poll request
} Try / catch
match login(&api_url) {
Err(e) if e.to_string().contains("device auth poll failed") => {
eprintln!("{}\nPolling failed; get a new code with `f auth`.", e);
}
other => other?,
} Prevention
- Back off on 429 and cap poll frequency
- Regenerate the device code via a fresh 'f auth' if the server rejects it
- Validate the start response fields before polling
- Verify the poll endpoint URL matches the current auth API version
When it happens
Trigger: POST to poll_url with {"device_code": ...} returns 4xx/5xx: device code malformed/expired server-side, wrong poll URL, rate limiting (429), or auth service outage.
Common situations: Polling too aggressively triggers 429; network/proxy intermittent failures; device_code corrupted because the start response failed to parse fields; API version mismatch changing the poll endpoint.
Related errors
- device auth start failed: HTTP {}
- Maple MCP request failed ({}): {}
- remote review failed: HTTP {}
- hub returned error: {}
- API error {}: {}
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/66278489e801ff3e.
Report an issue: GitHub.