{"record":{"id":"a8ea2d62b49545c7","repo":"nikivdev/code","slug":"device-code-expired-run-f-auth-again","errorCode":null,"errorMessage":"device code expired. Run `f auth` again.","messagePattern":"device code expired\\. Run `f auth` again\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/auth.rs","lineNumber":100,"sourceCode":"        if !poll_response.status().is_success() {\n            bail!(\"device auth poll failed: HTTP {}\", poll_response.status());\n        }\n\n        let poll: DevicePollResponse = poll_response\n            .json()\n            .context(\"failed to parse device auth poll response\")?;\n\n        match poll.status.as_str() {\n            \"approved\" => {\n                let token = poll\n                    .token\n                    .ok_or_else(|| anyhow!(\"device auth approved without token\"))?;\n                env::save_ai_auth_token(token, Some(api_url.clone()))?;\n                println!(\"✓ Auth complete. You're ready to use Flow AI.\");\n                return Ok(());\n            }\n            \"pending\" => continue,\n            \"expired\" => bail!(\"device code expired. Run `f auth` again.\"),\n            \"invalid\" => bail!(\"device code invalid. Run `f auth` again.\"),\n            other => bail!(\"unexpected auth status: {}\", other),\n        }\n    }\n\n    bail!(\"device code expired. Run `f auth` again.\")\n}\n\nfn open_in_browser(url: &str) {\n    #[cfg(target_os = \"macos\")]\n    {\n        let _ = std::process::Command::new(\"open\").arg(url).status();\n    }\n\n    #[cfg(target_os = \"linux\")]\n    {\n        let _ = std::process::Command::new(\"xdg-open\").arg(url).status();\n    }","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/auth.rs#L82-L118","documentation":"When the poll loop receives status \"expired\" from the auth server — or the retry deadline elapses without approval — login aborts telling the user to run 'f auth' again. Device codes are short-lived by design; this is the normal 'user took too long to authorize' termination path.","triggerScenarios":"Poll status equals \"expired\", or the loop exhausts its iterations/time budget and falls through to the final bail at the end of login.","commonSituations":"User waits past the code's TTL before opening the verification URL; machine clock skew makes the client stop polling early; polling loop bound too tight for slow approvals.","solutions":["Run 'f auth' again to get a fresh device code (this is the only remedy once expired)","Authorize promptly: open the verification URL as soon as it's displayed","Check system clock (NTP) if expiry seems premature","Extend the client-side retry deadline if your auth server's codes last longer than the loop budget"],"exampleFix":"// before\n\"expired\" => bail!(\"device code expired. Run `f auth` again.\"),\n// after\n\"expired\" => {\n    eprintln!(\"device code expired; requesting a new one...\");\n    return login(api_url); // restart flow with a fresh device code\n}","handlingStrategy":"retry","validationCode":"// Track elapsed time and warn the user before expiry\nlet deadline = Instant::now() + code_ttl;\nif Instant::now() > deadline - Duration::from_secs(60) {\n    eprintln!(\"Device code is about to expire — authorize now!\");\n}","typeGuard":null,"tryCatchPattern":"match login(&api_url) {\n    Err(e) if e.to_string().contains(\"device code expired\") => {\n        eprintln!(\"Code expired; starting a new login...\");\n        return login(&api_url); // one automatic re-attempt\n    }\n    other => other,\n}","preventionTips":["Open the verification URL immediately when shown","Set a client-side deadline comfortably under the server's code TTL","Sync system clock via NTP to avoid premature expiry","Offer one automatic restart of the flow on expiry"],"tags":["authentication","device-auth","timeout"],"backgroundTag":"device-code-expired","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}