{"record":{"id":"a8b2131279d30ade","repo":"zeroclaw-labs/zeroclaw","slug":"no-oauth-code-provided","errorCode":null,"errorMessage":"No OAuth code provided","messagePattern":"No OAuth code provided","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/gemini_oauth.rs","lineNumber":492,"sourceCode":"            WARN,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                .with_attrs(::serde_json::json!({\n                    \"oauth_provider\": \"gemini\",\n                    \"missing\": \"state\",\n                })),\n            \"gemini_oauth: callback missing state parameter\"\n        );\n        anyhow::Error::msg(\"No 'state' parameter in callback\")\n    })?;\n\n    Ok((code, state))\n}\n\npub fn parse_code_from_redirect(input: &str, expected_state: Option<&str>) -> Result<String> {\n    let trimmed = input.trim();\n    if trimmed.is_empty() {\n        anyhow::bail!(\"No OAuth code provided\");\n    }\n\n    // Extract query string\n    let query = if let Some((_, right)) = trimmed.split_once('?') {\n        right\n    } else {\n        trimmed\n    };\n\n    let params = parse_query_params(query);\n\n    // If we have code param, extract it\n    if let Some(code) = params.get(\"code\") {\n        // Validate state if expected\n        if let Some(expected) = expected_state\n            && let Some(actual) = params.get(\"state\")\n            && actual != expected\n        {","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/gemini_oauth.rs#L474-L510","documentation":"parse_code_from_redirect trims its input and bails immediately when the result is empty. The function accepts a full callback URL, a bare query string, or a raw authorization code, so an all-whitespace input is the one case it can definitively reject as 'nothing was provided'. It is reached via receive_code_from_stdin (user pressed Enter on an empty line) and via parse_code_from_url/parse_code_from_raw wrappers.","triggerScenarios":"The stdin fallback prompt is shown (loopback bind failed or callback timed out) and the user hits Enter without typing anything; a caller passes an empty string or whitespace-only string to parse_code_from_redirect, parse_code_from_url, or parse_code_from_raw.","commonSituations":"Headless/remote login where the user presses Enter accidentally; an automation script feeds an unset environment variable or empty clipboard content into the paste prompt.","solutions":["Paste the full callback URL (http://localhost:1456/auth/callback?code=...&state=...) or just the raw code, then press Enter","If scripting the input, guard that the variable is non-empty before piping it to the prompt"],"exampleFix":"// before\nlet code = parse_code_from_redirect(&input, Some(&state))?; // input may be empty\n\n// after\nlet input = input.trim();\nif input.is_empty() {\n    anyhow::bail!(\"paste the full callback URL or the raw authorization code\");\n}\nlet code = parse_code_from_redirect(input, Some(&state))?;","handlingStrategy":"validation","validationCode":"let trimmed = input.trim();\nif trimmed.is_empty() {\n    eprintln!(\"nothing was pasted; paste the full callback URL or the raw code\");\n    return;\n}\nlet code = parse_code_from_redirect(trimmed, Some(&expected_state))?;","typeGuard":null,"tryCatchPattern":"if let Err(e) = parse_code_from_redirect(&raw, expected_state) {\n    if e.to_string() == \"No OAuth code provided\" {\n        // re-prompt the user instead of failing the whole login\n        continue;\n    }\n    return Err(e);\n}","preventionTips":["Trim and check for empty input before feeding the parser","In scripts, assert the pasted variable is set and non-empty","Re-prompt on empty stdin rather than aborting the login"],"tags":["oauth","user-input","stdin","authorization-code","rust"],"backgroundTag":"oauth-code-parse-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}