{"record":{"id":"a7833316d1355dca","repo":"xai-org/grok-build","slug":"device-code-expired-run-grok-login-device-auth","errorCode":null,"errorMessage":"Device code expired. Run `grok login --device-auth` again.","messagePattern":"Device code expired\\. Run `grok login --device-auth` again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/device_code.rs","lineNumber":229,"sourceCode":"    surface: ClientSurface,\n) -> anyhow::Result<(GrokAuth, bool)> {\n    let client = crate::http::shared_client();\n    let token_url = format!(\"{}/oauth2/token\", issuer.trim_end_matches('/'));\n    let mut poll_interval = std::time::Duration::from_secs(device_code.interval.max(1) as u64);\n    let deadline = tokio::time::Instant::now()\n        + std::time::Duration::from_secs(\n            device_code\n                .expires_in\n                .max(MIN_DEVICE_CODE_EXPIRY_FALLBACK_SECS) as u64,\n        );\n\n    loop {\n        // Sleep first: an immediate poll on a fresh code only returns\n        // authorization_pending (and risks slow_down).\n        tokio::time::sleep(poll_interval).await;\n\n        if tokio::time::Instant::now() > deadline {\n            anyhow::bail!(\"Device code expired. Run `grok login --device-auth` again.\");\n        }\n\n        let resp = with_alpha_test_key(\n            client\n                .post(&token_url)\n                .header(\"x-grok-client-version\", xai_grok_version::VERSION)\n                .header(\"x-grok-client-surface\", surface.as_str())\n                .form(&[\n                    (\"grant_type\", DEVICE_GRANT_TYPE),\n                    (\"device_code\", device_code.device_code.as_str()),\n                    (\"client_id\", client_id),\n                ]),\n            &token_url,\n        )\n        .send()\n        .await?;\n\n        if resp.status().is_success() {","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/device_code.rs#L211-L247","documentation":"complete_device_code_login polls the token endpoint until a deadline computed from the device code's expires_in. If the deadline passes before the user completes authorization, the client stops polling and tells the user to restart the device login, because the server would reject the device_code anyway.","triggerScenarios":"complete_device_code_login's poll loop exceeds `deadline` (now > deadline) while the token endpoint keeps returning authorization_pending or slow_down — raised by request_device_code callers run_device_code_login_channels and prompt_and_poll.","commonSituations":"User waits too long to open the verification URL or enter the code; polling repeatedly hits slow_down and the interval grows past the expiry; device flow started headlessly and the user never saw the prompt.","solutions":["Re-run `grok login --device-auth` to obtain a fresh device code and complete it promptly.","Open the verification_uri and enter the user_code as soon as the prompt appears.","Check clock skew (NTP) if the code expires much earlier than expected.","For automation, pre-authorize via a non-interactive auth method (XAI_API_KEY or standard `grok login`) instead of device flow."],"exampleFix":"// before: start flow, get distracted, poll expires\n// after: restart promptly\ngrok login --device-auth\n# open https://x.ai/device and enter the new code within the expiry window","handlingStrategy":"retry","validationCode":"// nothing to check pre-call; but honor expires_in so you can warn the user early\nlet deadline = std::time::Instant::now() + std::time::Duration::from_secs(resp.expires_in);","typeGuard":null,"tryCatchPattern":"loop {\n    match complete_device_code_login(&client, &pending).await {\n        Err(e) if e.to_string().contains(\"Device code expired\") => {\n            eprintln!(\"Code expired; restarting device login...\");\n            pending = request_device_code(&client, &cfg).await?;\n        }\n        Ok(auth) => break auth,\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Authorize immediately when the verification URL appears.","Surface expires_in to the user with a visible countdown.","Ensure system clock sync (NTP) on headless machines.","Prefer API-key or browser login for unattended automation."],"tags":["oauth","device-flow","timeout"],"backgroundTag":"device-code-expired","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}