nautechsystems/nautilus_trader · error · TransportError

Invalid WebSocket reconnect header value: {e}

Error message

Invalid WebSocket reconnect header value: {e}

What it means

The reconnect header update API validates the value with HeaderValue::from_str. Header values must be visible ASCII (no control characters, no non-ASCII/UTF-8 multibyte content, no raw newlines). If the value fails validation, this InvalidInput TransportError is returned and the header is not stored. It is a caller input problem detected before any network I/O.

Source

Thrown at crates/network/src/websocket/client.rs:2282

        Self {
            inner: Arc::new(RwLock::new(headers)),
        }
    }

    /// Replaces a header used by future automatic reconnect attempts.
    ///
    /// # Errors
    ///
    /// Returns an error if the header name or value is invalid.
    pub fn update(&self, name: &str, value: &str) -> Result<(), TransportError> {
        let name = HeaderName::from_bytes(name.as_bytes()).map_err(|e| {
            TransportError::Io(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!("Invalid WebSocket reconnect header name: {e}"),
            ))
        })?;
        HeaderValue::from_str(value).map_err(|e| {
            TransportError::Io(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!("Invalid WebSocket reconnect header value: {e}"),
            ))
        })?;

        let name = name.as_str();
        let mut headers = self.inner.write();
        headers.retain(|(existing, _)| !existing.eq_ignore_ascii_case(name));
        headers.push((name.to_string(), value.to_string()));
        Ok(())
    }

    fn snapshot(&self) -> Vec<(String, String)> {
        self.inner.read().clone()
    }
}

impl Debug for ReconnectHeaders {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Trim whitespace/newlines from the value before calling update (value.trim())
  2. Ensure the value is pure visible ASCII; re-encode or fix the source of the credential if it contains other bytes
  3. Validate the value in your config-loading layer before constructing the client

Example fix

// before
let key = std::fs::read_to_string("key.txt")?; // may contain trailing \n
headers.update("X-Api-Key", &key)?;
// after
let key = std::fs::read_to_string("key.txt")?.trim().to_string();
headers.update("X-Api-Key", &key)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_header_value(v: &str) -> bool {
    !v.is_empty() && v.bytes().all(|b| (32..=126).contains(&b) || b == b'\t')
}
let value = raw_value.trim(); // strip file/env newlines

Try / catch

match headers.update(name, &value) {
    Err(e) if e.to_string().contains("header value") => return Err(InvalidConfig("header value must be visible ASCII".into())),
    r => r?,
}

Prevention

When it happens

Trigger: Calling update(name, value) where value contains characters outside visible ASCII range, control characters, or embedded newlines — e.g. tokens read from files with trailing newline, or credentials with unicode characters.

Common situations: Reading API keys from files/env without trimming (embedded \n or \r); non-ASCII secrets or unicode quotes pasted into config; logging/formatted values containing control characters.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/e5c79502e994a0fc. Report an issue: GitHub.