Azure-compatible enterprise proxy endpoints fail with "stream closed before response.completed" due to unsupported include and client_metadata fields
What version of Codex CLI is running?
0.120.0
What subscription do you have?
Enterprise
Which model were you using?
gpt-5.2-codex
What platform is your computer?
Darwin 25.4.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
iTerm2
What issue are you seeing?
Environment
- Provider type: Azure-compatible enterprise OpenAI proxy (wire_api = "responses")
- Model:
gpt-5.2-codex(any model withsupports_reasoning_summaries: true) - Config:
model_reasoning_effortset (e.g.xhigh)
## Bug
When using Codex with an Azure-compatible enterprise OpenAI proxy, every request fails immediately with:
````
■ stream disconnected before completion: stream closed before response.completed
The stream returns HTTP 200 but closes with an empty body, never emitting response.completed.
## Root Cause
build_responses_request() in codex-rs/core/src/client.rs sends two fields that Azure-compatible proxies do not support:
1. "reasoning.encrypted_content" in include
When reasoning.is_some(), the request always includes:
``json``
"include": ["reasoning.encrypted_content"]
Azure/enterprise proxies reject this with {"detail": "Internal server error"}.
2. client_metadata
The request always includes:
``json``
"client_metadata": {"x-codex-installation-id": "<id>"}
Azure/enterprise proxies silently return HTTP 200 with an empty body when this field is present, triggering the "stream closed before response.completed"
error.
Both fields are OpenAI.com-internal and are already correctly skipped in other parts of the codebase using the existing
provider.is_azure_responses_endpoint() guard — but build_responses_request() was missing these guards.
## Proposed Fix
In codex-rs/core/src/client.rs, build_responses_request():
```rust
// Before
let include = if reasoning.is_some() {
vec!["reasoning.encrypted_content".to_string()]
} else {
Vec::new()
};
// After
let include = if reasoning.is_some() && !provider.is_azure_responses_endpoint() {
vec!["reasoning.encrypted_content".to_string()]
} else {
Vec::new()
};
```
```rust
// Before
client_metadata: Some(HashMap::from([(
X_CODEX_INSTALLATION_ID_HEADER.to_string(),
self.client.state.installation_id.clone(),
)])),
// After
client_metadata: if !provider.is_azure_responses_endpoint() {
Some(HashMap::from([(
X_CODEX_INSTALLATION_ID_HEADER.to_string(),
self.client.state.installation_id.clone(),
)]))
} else {
None
},
``is_azure_responses_endpoint()` helper, consistent with how the rest of the codebase handles Azure/enterprise endpoints.
Both changes reuse the existing
What steps can reproduce the bug?
Use CLI with given parameters.
What is the expected behavior?
_No response_
Additional information
_No response_
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗