{"record":{"id":"3c6e162d47eddfdf","repo":"warpdotdev/warp","slug":"unexpected-non-terminal-oauth-status-returned","errorCode":null,"errorMessage":"Unexpected non-terminal OAuth status returned","messagePattern":"Unexpected non-terminal OAuth status returned","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"app/src/ai/agent_sdk/environment.rs","lineNumber":667,"sourceCode":"                                                Some(Err(anyhow::anyhow!(\n                                                    \"GitHub authorization failed. Please try again.\"\n                                                ))),\n                                            );\n                                        }\n                                        Ok(OauthConnectTxStatus::Expired) => {\n                                            ctx.terminate_app(\n                                                warpui::platform::TerminationMode::ForceTerminate,\n                                                Some(Err(anyhow::anyhow!(\n                                                    \"GitHub authorization expired. Please try again.\"\n                                                ))),\n                                            );\n                                        }\n                                        Ok(OauthConnectTxStatus::Pending)\n                                        | Ok(OauthConnectTxStatus::InProgress) => {\n                                            // Should not be returned by poll_oauth_until_terminal.\n                                            ctx.terminate_app(\n                                                warpui::platform::TerminationMode::ForceTerminate,\n                                                Some(Err(anyhow::anyhow!(\n                                                    \"Unexpected non-terminal OAuth status returned\"\n                                                ))),\n                                            );\n                                        }\n                                        Err(err) => {\n                                            ctx.terminate_app(\n                                                warpui::platform::TerminationMode::ForceTerminate,\n                                                Some(Err(anyhow::anyhow!(\n                                                    \"Error polling OAuth status: {err}\"\n                                                ))),\n                                            );\n                                        }\n                                    }\n                                },\n                            );\n                        }\n                        (Some(auth_url), None) => {\n                            // Legacy flow: no txId, print URL and exit.","sourceCodeStart":649,"sourceCodeEnd":685,"githubUrl":"https://github.com/warpdotdev/warp/blob/e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc/app/src/ai/agent_sdk/environment.rs#L649-L685","documentation":"Defensive invariant violation in the OAuth poll handler: poll_oauth_until_terminal is contractually supposed to loop until a terminal status, but it returned Ok with Pending or InProgress. The match arm's comment says 'Should not be returned by poll_oauth_until_terminal'. Reaching this error indicates a bug or behavioral change in the poll helper (or the server returning an unexpected status ordering), not a user mistake.","triggerScenarios":"A change to poll_oauth_until_terminal (app/src/ai/agent_sdk/oauth_flow.rs) that lets non-terminal statuses escape; a server status response that the client maps to Pending/InProgress on the final poll iteration; refactoring that broke the loop's terminal-status guarantee.","commonSituations":"Client/server version mismatch after a server adds a new status value; recent code changes to the oauth_flow helper; race where the poll future completes on a non-terminal snapshot.","solutions":["Re-run the command — if transient, the next poll cycle usually completes","Update the Warp client; the poll helper and server contract may be aligned in a newer build","If you develop on this repo, fix poll_oauth_until_terminal so non-terminal statuses cannot be returned (keep polling instead)","Report it with logs — this arm exists precisely to surface contract violations"],"exampleFix":"// before (oauth_flow.rs concept: returning early on any Ok status)\nlet status = client.get_tx_status(tx).await?;\nOk(status)\n\n// after (loop until terminal)\nloop {\n    let status = client.get_tx_status(tx).await?;\n    match status {\n        OauthConnectTxStatus::Pending | OauthConnectTxStatus::InProgress => continue,\n        terminal => return Ok(terminal),\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Ok(OauthConnectTxStatus::Pending | OauthConnectTxStatus::InProgress) => {\n    // contract violation from poll_oauth_until_terminal: log loudly, retry once,\n    // and report upstream if reproducible\n}","preventionTips":["Keep the client updated — poll-helper fixes ship with newer builds","If you fork/patch oauth_flow.rs, guarantee the poll loop only returns terminal statuses","Capture logs when this fires; it indicates a code/server contract bug, not user error","Re-run the command once before assuming a persistent defect"],"tags":["rust","oauth","invariant","bug","polling"],"backgroundTag":null,"analyzedSha":"e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc","analyzedAt":"2026-08-16T08:27:25.381Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}