{"record":{"id":"6bbee145922c340c","repo":"xai-org/grok-build","slug":"token-exchange-error-detail","errorCode":null,"errorMessage":"Token exchange error: {detail}","messagePattern":"Token exchange error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/device_code.rs","lineNumber":278,"sourceCode":"            \"slow_down\" => {\n                poll_interval += std::time::Duration::from_secs(DEVICE_SLOW_DOWN_INCREMENT_SECS);\n                continue;\n            }\n            \"access_denied\" => {\n                tracing::warn!(description = detail, \"device auth authorization denied\");\n                anyhow::bail!(\"Authorization denied. The user rejected the request.\");\n            }\n            \"expired_token\" => {\n                tracing::warn!(description = detail, \"device auth token expired\");\n                anyhow::bail!(\"Device code expired. Run `grok login --device-auth` again.\");\n            }\n            other => {\n                tracing::warn!(\n                    error = other,\n                    description = detail,\n                    \"device auth token exchange failed\"\n                );\n                anyhow::bail!(\"Token exchange error: {detail}\");\n            }\n        }\n    }\n}\n\n/// Device-code login shared by the TUI and CLI.\n///\n/// With `channels` (TUI) the verification URL goes to `url_tx` and the browser\n/// opens automatically; on failure the copyable URL is the fallback. Without\n/// `channels` (CLI) the URL + code are printed to stderr via `prompt_and_poll`.\n/// `code_rx` is unused here. The caller reports success (`✓ Signed in`).\n///\n/// Takes `channels` by `&mut`, consuming it only after the device code is\n/// obtained, so callers can reuse it for a loopback fallback on `NotEnabled`.\npub(crate) async fn run_device_code_login_channels(\n    issuer: &str,\n    client_id: &str,\n    scopes: &[String],","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/device_code.rs#L260-L296","documentation":"Catch-all branch: the token endpoint returned an unrecognized OAuth2 error code during device-code exchange. The client logs the raw error and detail and aborts with the server's description so the developer can diagnose the actual server-side cause.","triggerScenarios":"complete_device_code_login gets a token response whose error field is not one of authorization_pending, slow_down, access_denied, or expired_token — e.g. invalid_grant, invalid_client, or server_error.","commonSituations":"Client credentials/client_id mismatch after a config change; reverse proxy or gateway injecting error responses (502/503 HTML parsed as error); server API version drift introducing new error codes; device_code already consumed.","solutions":["Read the `detail` in the message — it contains the server's error description.","Verify the client_id/OAuth2 configuration (grok_com_config.oauth2) matches the issuer.","Check the authorization server's status/logs for outages or gateway errors.","Retry once with a fresh device code; if persistent, update the client or report the unhandled error code."],"exampleFix":"// server response example causing it\n{\"error\": \"invalid_grant\", \"error_description\": \"device_code already used\"}\n// fix: do not reuse a device code; start a new login\ngrok login --device-auth","handlingStrategy":"try-catch","validationCode":"// pre-flight: confirm the token endpoint is reachable and returns JSON\ncurl -sS -o /dev/null -w '%{http_code}' https://x.ai/oauth/token","typeGuard":null,"tryCatchPattern":"match complete_device_code_login(&client, &pending).await {\n    Err(e) if e.to_string().starts_with(\"Token exchange error\") => {\n        eprintln!(\"Server said: {e}. Check client_id config and issuer status, then retry.\");\n    }\n    other => other?,\n}","preventionTips":["Keep OAuth2 client_id/issuer config in sync with server expectations.","Monitor the authorization server for gateway/proxy error injection.","Never reuse a device_code after a successful or failed exchange.","Update the client when the server introduces new OAuth2 error codes."],"tags":["oauth","device-flow","token-exchange"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}