{"record":{"id":"c22535d78635b931","repo":"xai-org/grok-build","slug":"oidcerror-bindloopback","errorCode":null,"errorMessage":"OidcError::BindLoopback","messagePattern":"OidcError::BindLoopback","errorType":"exception","errorClass":"OidcError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/oidc/login.rs","lineNumber":400,"sourceCode":"    )\n    .ok();\n\n    let discovery = discover(&oidc.issuer).await?;\n    let pkce = generate_pkce();\n    let state = uuid::Uuid::now_v7().to_string();\n    let nonce = uuid::Uuid::now_v7().to_string();\n\n    // In local-dev mode, use a fixed callback port so the redirect_uri is stable\n    // and can be pre-registered with the local OAuth2 provider. In production the\n    // OS picks a random available port.\n    let callback_port: u16 = if super::super::config::use_local_auth() {\n        56121\n    } else {\n        0\n    };\n    let listener = TcpListener::bind((\"127.0.0.1\", callback_port))\n        .await\n        .map_err(|e| anyhow::Error::new(OidcError::BindLoopback(e.to_string())))?;\n    let port = listener.local_addr()?.port();\n    let redirect_uri = format!(\"http://127.0.0.1:{}/callback\", port);\n    let oauth2 = auth_manager.grok_com_config().oauth2.as_ref();\n    let auth_url = build_authorize_url(\n        oidc,\n        oauth2,\n        &discovery,\n        &redirect_uri,\n        &pkce,\n        &state,\n        &nonce,\n    );\n    tracing::debug!(port = port, redirect_uri = %redirect_uri, \"OIDC: callback server bound\");\n\n    let (url_tx, code_rx) = match channels {\n        Some(ch) => (ch.url_tx, Some(ch.code_rx)),\n        None => (None, None),\n    };","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/oidc/login.rs#L382-L418","documentation":"The OIDC login flow binds a local TCP listener on 127.0.0.1 (fixed port 56121, or an ephemeral port 0) to receive the OAuth redirect. This error wraps the std::io error when `TcpListener::bind((\"127.0.0.1\", callback_port))` fails, so the flow cannot start the loopback callback server.","triggerScenarios":"TcpListener::bind on 127.0.0.1 fails in run_login_flow_with_config — typically port 56121 already in use, or binding to loopback is disallowed.","commonSituations":"Another instance of the tool (or a stale process) is still holding port 56121; another dev server occupies the port; container/sandbox with no loopback networking; strict firewall/SELinux policy; IPv6-only environment where 127.0.0.1 binding is restricted.","solutions":["Find and kill the process holding the port: `lsof -i :56121` then terminate the stale process.","Re-run the login — if the config uses port 0 (ephemeral), a retry picks a free port.","Configure a different fixed callback port in the OIDC config, updating the IDP's allowed redirect_uri to match.","Verify loopback networking is available (not blocked in the container/sandbox) and no firewall rule forbids binding to 127.0.0.1."],"exampleFix":"// before\n$ lsof -i :56121\nCOMMAND   PID USER ...\nold-grok 1234 dev\n$ kill 1234  # free the port, then retry login\n// after\n$ grok login  # binds 127.0.0.1:56121 successfully","handlingStrategy":"retry","validationCode":"// preflight: check the fixed callback port is free before starting login\nlet port_free = std::net::TcpListener::bind((\"127.0.0.1\", 56121)).is_ok();\nif !port_free {\n    eprintln!(\"port 56121 is in use; kill the stale process or switch to an ephemeral port\");\n}","typeGuard":"fn is_bind_loopback(err: &anyhow::Error) -> bool {\n    err.downcast_ref::<OidcError>()\n        .map_or(false, |e| matches!(e, OidcError::BindLoopback(_)))\n}","tryCatchPattern":"if is_bind_loopback(&err) {\n    // common cause: address already in use — brief backoff then retry\n    tokio::time::sleep(Duration::from_secs(2)).await;\n    return run_login_flow(config, auth_manager, channels).await;\n}","preventionTips":["Check `lsof -i :56121` for stale processes before login","Prefer ephemeral ports (callback_port = 0) when the IDP allows wildcard redirect URIs","Ensure the environment permits loopback binding (containers, sandboxes, SELinux)","Update the IDP redirect allowlist when changing the fixed port"],"tags":["network","bind-failed","port-in-use","oidc"],"backgroundTag":"address-already-in-use","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}