{"record":{"id":"afe2031d67c209aa","repo":"nikivdev/code","slug":"device-code-invalid-run-f-auth-again","errorCode":null,"errorMessage":"device code invalid. Run `f auth` again.","messagePattern":"device code invalid\\. Run `f auth` again\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/auth.rs","lineNumber":101,"sourceCode":"            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    }\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/auth.rs#L83-L119","documentation":"In `login` (src/auth.rs:101), the OAuth device-flow poll loop asks the auth server for the device-code status; when the server replies with status \"invalid\" the CLI bails with this message. It means the device code or user code the server received was rejected — typically it was already consumed, revoked, or mistyped. The remedy is to restart `f auth` to get a fresh code.","triggerScenarios":"Calling `f auth`, the poll endpoint returns status \"invalid\" — e.g. the device code expired and was reaped, the code was already redeemed by a prior login, or the server invalidated the session mid-poll.","commonSituations":"User leaves the auth prompt open too long, runs `f auth` twice in parallel and one redeems the code, or the auth server rotates/invalidates codes after a version change or clock drift.","solutions":["Run `f auth` again to get a fresh device code","Complete browser authorization promptly instead of leaving the prompt idle","Avoid running two `f auth` sessions concurrently","Check the auth server URL configured for Flow AI is current"],"exampleFix":"// before\nbail!(\"device code invalid. Run `f auth` again.\");\n// after\n// automatic re-request of a fresh device code instead of failing:\n// let (code, url) = start_device_flow(...)?; continue;\nbail!(\"device code invalid. Run `f auth` again.\"); // unchanged: manual restart is the intended UX","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Rust caller\nmatch f_auth_login() {\n    Err(e) if e.to_string().contains(\"device code invalid\") => {\n        eprintln!(\"Code rejected — restarting device flow...\");\n        f_auth_login()?; // retry once with a fresh code\n    }\n    other => other?,\n}","preventionTips":["Complete browser approval as soon as the code is shown","Never run two `f auth` sessions at once","Keep the CLI and auth server versions in sync"],"tags":["auth","oauth-device-flow","cli"],"backgroundTag":"device-code-invalid","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}