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

  1. Confirm the provider base URL is reachable and supports wss.
  2. Allow WebSocket upgrades through the proxy or firewall.
  3. Raise websocket_connect_timeout for the provider if the link is legitimately slow.
  4. 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

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

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/213db1feec089e2b. Report an issue: GitHub.