openai/codex · error · io::Error
network proxy attribution environment mismatch
Error message
network proxy attribution environment mismatch
What it means
The attribution token resolved to a registered execution, but the ingress was constructed with an expected environment id and the token's state carries a different one, so the connection is rejected with PermissionDenied. This is a deliberate isolation check in BindConnectionAttribution::serve: traffic attributed to an execution from another environment must not be routed through this ingress. It only fires when the bind supplied an environment_id AND the resolved state's environment_id is set and differs.
Source
Thrown at codex-rs/network-proxy/src/attribution.rs:63
type Output = S::Output;
type Error = BoxError;
async fn serve(&self, mut stream: TcpStream) -> Result<Self::Output, Self::Error> {
let state = match read_attribution_token(&mut stream).await? {
Some(token) => self.state.for_execution_token(&token).ok_or_else(|| {
io::Error::new(
io::ErrorKind::PermissionDenied,
"unknown network proxy attribution token",
)
})?,
None => self.state.as_ref().clone(),
};
if let Some(expected_environment_id) = self.environment_id.as_deref()
&& state
.environment_id()
.is_some_and(|actual| actual != expected_environment_id)
{
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"network proxy attribution environment mismatch",
)
.into());
}
stream.extensions_mut().insert(Arc::new(state));
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);View on GitHub (pinned to 339751715c)
Solutions
- Use a token minted in the same environment the ingress was bound to -- re-export CODEX_NETWORK_PROXY_ATTRIBUTION inside that environment and reconnect.
- Verify the environment id passed at bind time matches the environment recorded for the token's execution in the registry.
- Restart bridge and proxy within one environment/session so both sides derive from the same configuration.
Example fix
// before: token exported in environment A, ingress bound to environment B
// $ export CODEX_NETWORK_PROXY_ATTRIBUTION=<token-from-env-A>
// after: obtain the token inside the environment the ingress serves
let token = env::var("CODEX_NETWORK_PROXY_ATTRIBUTION")?; // read within env B's execution Defensive patterns
Strategy: validation
Validate before calling
// If both ids are visible to the client, compare before dialing
if let (Some(expected), Some(actual)) = (bind_environment_id, token_environment_id) {
if expected != actual {
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"attribution token belongs to a different environment",
));
}
} Try / catch
Match io::ErrorKind::PermissionDenied whose message contains 'environment mismatch': surface it as a configuration error (wrong environment for this token); do not retry -- retrying cannot change the environment.
Prevention
- Source the token and the proxy bind config from the same environment descriptor.
- Do not copy CODEX_NETWORK_PROXY_ATTRIBUTION between containers/workspaces.
- Log both environment ids when the check fails so the mismatch is obvious.
When it happens
Trigger: The ingress is built via BindConnectionAttribution::new(..., Some(expected_env)) while the client presents a token minted inside a different environment id -- e.g. a token exported in devcontainer A used against an ingress bound to devcontainer B.
Common situations: Copying CODEX_NETWORK_PROXY_ATTRIBUTION between shells or containers of different environments; environment/workspace renamed so bind config and token registry disagree; multi-environment test setups mixing tokens.
Related errors
- unknown network proxy attribution token
- InvalidInput
- empty proxy connection
- invalid network proxy attribution frame
- invalid network proxy attribution token length
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/11bb0f5aae1aaa80.
Report an issue: GitHub.