openai/codex · error · TransportError

request build error: {0}

Error message

request build error: {0}

What it means

TransportError::Build is returned by ReqwestTransport::build (transport.rs:53) when Request::prepare_body_for_send() fails to turn the request into wire bytes. The string is the exact reason from request.rs: 'request compression cannot be used with raw bodies', 'request compression was requested but content-encoding is already set', a serde_json serialization error, or a zstd compression error. It fires before any network I/O, so it is deterministic and retrying will not help.

Source

Thrown at codex-rs/http-client/src/error.rs:25

#[derive(Debug, Error)]
pub enum TransportError {
    #[error("http {status}: {body:?}")]
    Http {
        status: StatusCode,
        url: Option<String>,
        headers: Option<HeaderMap>,
        body: Option<String>,
    },
    #[error("retry limit reached")]
    RetryLimit,
    #[error("timeout")]
    Timeout,
    #[error("connection failed: {0}")]
    Connection(#[source] HttpError),
    #[error("network error: {0}")]
    Network(String),
    #[error("request build error: {0}")]
    Build(String),
}

#[derive(Debug, Error)]
pub enum StreamError {
    #[error("stream failed: {0}")]
    Stream(String),
    #[error("timeout")]
    Timeout,
}

View on GitHub (pinned to 339751715c)

Solutions

  1. Read the message string: it names the exact conflict (raw body + compression, or existing content-encoding)
  2. Do not combine RequestCompression with RequestBody::Raw: send JSON bodies or disable compression for raw payloads
  3. Remove any manually inserted Content-Encoding header before requesting compression and let prepare_encoded_json insert 'zstd' itself
  4. Call Request::into_prepared() at construction time to surface this failure early with full context instead of at send time

Example fix

// before
let mut req = Request::new(Method::POST, url).with_json(&body)
    .with_compression(RequestCompression::Zstd);
req.headers.insert(http::header::CONTENT_ENCODING,
    http::HeaderValue::from_static("gzip")); // -> Build("content-encoding is already set")

// after: let the transport own Content-Encoding when compressing
let req = Request::new(Method::POST, url).with_json(&body)
    .with_compression(RequestCompression::Zstd);
Defensive patterns

Strategy: validation

Validate before calling

// Dry-run the exact wire preparation before handing the request to the transport
fn request_builds(req: &Request) -> Result<(), String> {
    req.prepare_body_for_send().map(|_| ())
}

Type guard

fn is_build_error(e: &TransportError) -> bool {
    matches!(e, TransportError::Build(_))
}

Try / catch

Err(TransportError::Build(reason)) => {
    // deterministic input problem: fail fast, do not retry
    return Err(ConfigError::RequestShape(reason));
}

Prevention

When it happens

Trigger: Building a Request with RequestBody::Raw combined with RequestCompression::Zstd; setting a manual Content-Encoding header while also requesting compression (request.rs:193-198); a JSON body whose encoding fails; a zstd encode_all failure (request.rs:204-208).

Common situations: Enabling zstd request compression uniformly in a pipeline where some callers already set Content-Encoding: gzip, or where some paths send raw (non-JSON) bodies; retrofitting compression onto existing request code without auditing headers.

Related errors


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