openai/codex · error · LunaSamplerError
Luna Responses WebSocket connection timed out
Error message
Luna Responses WebSocket connection timed out
What it means
The provider's websocket_connect_timeout elapsed before the Responses WebSocket handshake completed (tokio::time::timeout around ResponsesWebsocketClient::connect). Also produced if the pool's capacity semaphore is closed. The sampler retries this variant up to 2 times before it escapes.
Source
Thrown at codex-rs/ext/guardian-v2/src/async_scorer/sampler.rs:116
/// Strict JSON schema constraining the model response.
pub output_schema: Value,
/// Reasoning budget explicitly selected for this request.
pub reasoning_effort: ReasoningEffort,
/// Owning turn identifier used for request attribution.
pub turn_id: String,
}
/// Failures returned while connecting or sampling the Luna model.
#[derive(Debug, Error)]
pub enum LunaSamplerError {
/// The thread's provider or scoped credentials could not be resolved.
#[error("could not resolve the Luna model provider: {0}")]
Provider(#[source] CodexErr),
/// The Responses WebSocket could not be opened or streamed.
#[error("Luna Responses WebSocket failed: {0}")]
Api(#[source] ApiError),
/// The provider's WebSocket connect deadline elapsed.
#[error("Luna Responses WebSocket connection timed out")]
ConnectionTimeout,
/// The response did not contain an assistant text value.
#[error("Luna response did not contain assistant output")]
MissingOutput,
/// The response exceeded the bounded output limit.
#[error("Luna response exceeded the output limit")]
OutputTooLarge,
/// A newer classification replaced this request when the pool was full.
#[error("Luna request was superseded by a newer classification")]
Superseded,
}
struct PooledConnection {
connection: ResponsesWebsocketConnection,
// The bridge routes by thread ID, so each socket needs its own identity.
thread_id: String,
expires_at: Instant,
auth_changes: Option<tokio::sync::watch::Receiver<u64>>,View on GitHub (pinned to 339751715c)
Solutions
- Confirm the provider base URL is reachable and supports wss.
- Allow WebSocket upgrades through the proxy or firewall.
- Raise websocket_connect_timeout for the provider if the link is legitimately slow.
- Check for a provider outage — the sampler has already retried twice when this surfaces.
Defensive patterns
Strategy: retry
Try / catch
match err {
LunaSamplerError::ConnectionTimeout if attempts < 3 => {
tokio::time::sleep(backoff(attempts)).await;
continue;
}
_ => return Err(err),
} Prevention
- Verify wss:// reachability through the egress proxy before enabling guardian-v2.
- Size websocket_connect_timeout to the link's real RTT.
- Prefer failing open (no classification) over blocking turns on persistent timeouts.
When it happens
Trigger: Connecting when the network is slow or blocks WebSocket upgrades (corporate proxy), the provider endpoint is down, or websocket_connect_timeout is too low for the link latency.
Common situations: Restrictive egress proxies stalling wss:// handshakes; high-latency VPN; self-hosted gateway with a short timeout; provider incident.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Luna Responses WebSocket failed: {0}
- timeout
- route-aware request timed out
- app-server closed the control socket
- Snapshot command timed out for {shell_name}
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/213db1feec089e2b.
Report an issue: GitHub.