openai/codex · error · io::Error
invalid network proxy attribution frame
Error message
invalid network proxy attribution frame
What it means
The first byte on the connection was NUL -- the first byte of the 8-byte magic b"\0CDXPXY1" -- so the ingress tried to read a full attribution frame, but the eight magic bytes did not match the constant. Rejected with io::ErrorKind::InvalidData. Meaning: the client speaks some other NUL-prefixed binary protocol, or wrote a corrupted, truncated, or wrong-version preface.
Source
Thrown at codex-rs/network-proxy/src/attribution.rs:88
self.inner.serve(stream).await.map_err(Into::into)
}
}
async fn read_attribution_token(stream: &mut TcpStream) -> Result<Option<String>, BoxError> {
let mut marker = [0_u8; 1];
let read = stream.stream.peek(&mut marker).await?;
if read == 0 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "empty proxy connection").into());
}
if marker[0] != ATTRIBUTION_FRAME_MAGIC[0] {
return Ok(None);
}
let token = tokio::time::timeout(ATTRIBUTION_FRAME_TIMEOUT, async {
let mut magic = [0_u8; ATTRIBUTION_FRAME_MAGIC.len()];
stream.read_exact(&mut magic).await?;
if &magic != ATTRIBUTION_FRAME_MAGIC {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"invalid network proxy attribution frame",
));
}
let token_len = stream.read_u16().await? as usize;
if token_len == 0 || token_len > MAX_ATTRIBUTION_TOKEN_LEN {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"invalid network proxy attribution token length",
));
}
let mut token = vec![0_u8; token_len];
stream.read_exact(&mut token).await?;
String::from_utf8(token).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"network proxy attribution token is not UTF-8",View on GitHub (pinned to 339751715c)
Solutions
- Stop hand-rolling the preface: call write_attribution_frame(writer, &token), which writes the exact magic constant.
- Build the full frame (magic + length + token) in one buffer and write_all it once right after connect.
- If builds are version-skewed, rebuild bridge and ingress from the same source so ATTRIBUTION_FRAME_MAGIC matches.
Example fix
// before: hand-written magic with a typo writer.write_all(b"\0CDXPXY2")?; // wrong constant // after: use the shipped helper codex_network_proxy::write_attribution_frame(&mut writer, &token)?;
Defensive patterns
Strategy: validation
Validate before calling
// Do not hand-roll bytes; route every preface through the helper use codex_network_proxy::write_attribution_frame; write_attribution_frame(&mut writer, &token)?; // writes the exact magic
Try / catch
Match io::ErrorKind::InvalidData whose message contains 'invalid network proxy attribution frame': stop and inspect the client's preface bytes (wrong magic constant or version skew); retrying the same bytes will fail identically.
Prevention
- Reuse write_attribution_frame instead of reimplementing the wire format.
- Write the complete frame in one write_all after connect.
- Rebuild bridge and ingress from the same revision so ATTRIBUTION_FRAME_MAGIC cannot drift.
When it happens
Trigger: A hand-rolled client writes a different magic (typo, stale constant, different protocol version); the preface write is split and the stream shifts; another binary protocol that happens to start with 0x00 is pointed at the ingress port.
Common situations: Reimplementing the frame format in another language instead of reusing write_attribution_frame; a magic-constant change between bridge and ingress builds (version skew); routing a non-codex NUL-first protocol to the proxy port.
Related errors
- invalid network proxy attribution token length
- network proxy attribution token is not UTF-8
- unknown network proxy attribution token
- network proxy attribution environment mismatch
- empty proxy connection
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/9b3f5e2ff7d745dc.
Report an issue: GitHub.