Kuberwastaken/claurst · error
Failed to accept connection
Error message
Failed to accept connection: {} What it means
The OAuth flow's local HTTP server failed to accept the incoming browser callback connection: `listener.accept()` returned an I/O error, which is wrapped into this message. This is an OS-level accept failure (e.g. socket closed, EMFILE too many open files), distinct from the timeout case.
Solutions
- Raise the file-descriptor limit (`ulimit -n 4096`) and retry the login.
- Check security software or container policies that interfere with loopback connections.
- Simply retry the OAuth flow — accept errors are usually transient.
- If reproducible, capture the underlying io::Error message for a bug report.
Example fix
// diagnose // $ ulimit -n # if low, raise before running // $ ulimit -n 4096 && ./claurst login
Defensive patterns
Strategy: retry
Validate before calling
// Check fd headroom before starting the flow // $ ulimit -n (raise to >=1024 if low)
Try / catch
match run_oauth_flow(&mut app).await {
Err(e) if e.to_string().contains("Failed to accept connection") => {
eprintln!("Transient accept failure; retrying login once");
run_oauth_flow(&mut app).await?;
}
other => other?,
} Prevention
- Raise the file-descriptor limit if you run many concurrent connections.
- Retry the login flow — accept failures are usually transient.
- Exclude localhost from security software that resets local sockets.
When it happens
Trigger: `listener.accept()` inside `wait_for_callback` returns `Err(io::Error)` — the listener socket was invalidated, the process hit the file-descriptor limit, or the connection was reset at the OS level.
Common situations: Process running with `ulimit -n` exhausted (many open files/sockets); container network namespace tearing down the loopback socket; antivirus/security software killing the local connection; system suspend during the wait.
Related errors
- Failed to bind port
- models endpoint returned
- Bridge register: server returned
- start_bridge: bridge is not active
- Missing code or state in OAuth callback
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/c9a272fbfc81a9e8.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/cli/src/codex_oauth_flow.rs:121
// Persist tokens and register an account profile in the registry.
claurst_core::oauth_config::save_codex_tokens_and_register(&tokens, label)?;
eprintln!("Codex login successful!");
Ok(tokens)
}
/// Wait for OAuth callback on local server, extract code and state.
async fn wait_for_callback(listener: TcpListener) -> anyhow::Result<(String, String)> {
use tokio::io::AsyncWriteExt;
let (mut socket, _) = tokio::time::timeout(
std::time::Duration::from_secs(300), // 5 minute timeout
listener.accept(),
)
.await
.map_err(|_| anyhow!("OAuth callback timeout (5 minutes)"))?
.map_err(|e| anyhow!("Failed to accept connection: {}", e))?;
let mut reader = BufReader::new(&mut socket);
let mut request_line = String::new();
reader.read_line(&mut request_line).await?;
// Parse "GET /auth/callback?code=...&state=... HTTP/1.1"
let parts: Vec<&str> = request_line.split_whitespace().collect();
if parts.len() < 2 {
bail!("Invalid HTTP request");
}
let path = parts[1];
let query_start = path.find('?').ok_or_else(|| anyhow!("No query string in callback"))?;
let query = &path[query_start + 1..];
let mut code = String::new();
let mut state = String::new();
let mut error = String::new();
View on GitHub (pinned to b0637c97ec)