Responses Lite sends an empty description for the default functions namespace, rejected by Azure OpenAI
What version of Codex CLI is running?
codex-cli 0.147.0
What subscription do you have?
API/custom model provider using Azure OpenAI through LiteLLM; not tied to a ChatGPT subscription.
Which model were you using?
gpt-5.6-sol
What platform is your computer?
Windows 11, arm64
What terminal emulator and version are you using (if applicable)?
PowerShell
Codex doctor report
{
"status": "not available for the affected Codex build"
}
What issue are you seeing?
When Responses Lite is enabled for a model and the provider supports namespace
tools, Codex groups normal function/custom tools into an additional_tools
item under the default functions namespace.
Codex serializes this namespace with an empty description:
{
"type": "namespace",
"name": "functions",
"description": "",
"tools": [...]
}
Azure OpenAI's Responses API rejects the request before inference:
HTTP 400
Invalid 'input[0].tools[0].description': empty string
Removing the field also fails:
Missing required parameter: 'input[0].tools[0].description'.
Changing only the description to a non-empty value, such as
"Built-in function tools", makes the same request succeed with HTTP 200.
This issue is conditional: it only occurs when the selected model has
use_responses_lite=true. Normal Responses requests do not reproduce it.
What steps can reproduce the bug?
1. Configure a Responses-compatible custom provider backed by Azure OpenAI.
2. Select a model whose metadata has `use_responses_lite=true`.
3. Ensure namespace tools are supported and start a normal Codex turn containing
function tools.
4. Inspect the generated Responses request.
5. Observe that the first `additional_tools` item contains a `functions`
namespace whose `description` is `""`.
6. Send the request to Azure OpenAI and observe HTTP 400.
Minimal relevant request shape:
```json
{
"model": "affected-model",
"input": [
{
"type": "additional_tools",
"role": "developer",
"tools": [
{
"type": "namespace",
"name": "functions",
"description": "",
"tools": [
{
"type": "function",
"name": "lookup_order",
"description": "Look up an order",
"parameters": {
"type": "object",
"properties": {}
}
}
]
}
]
},
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Reply only: ok."
}
]
}
]
}
### What is the expected behavior?
```markdown
Codex should not emit an empty required namespace description.
Possible fixes include:
- use a non-empty default such as `"Built-in function tools"` for the
`functions` namespace;
- normalize empty descriptions for non-OpenAI/Azure providers; or
- disable Responses Lite namespace serialization when the configured provider
cannot accept that wire format.
Existing non-empty namespace descriptions should remain unchanged.
Additional information
Current source explicitly creates and preserves this empty value:
codex-rs/tools/src/responses_api.rs:
default_namespace_description("functions") returns String::new().
codex-rs/tools/src/tool_spec_tests.rs:
responses_lite_preserves_empty_functions_namespace_description asserts that
the serialized description equals "".
codex-rs/core/tests/suite/responses_lite.rsalso asserts the empty
description in the generated additional_tools request.
Relevant source:
https://github.com/openai/codex/blob/main/codex-rs/tools/src/responses_api.rs
https://github.com/openai/codex/blob/main/codex-rs/tools/src/tool_spec.rs
https://github.com/openai/codex/blob/main/codex-rs/tools/src/tool_spec_tests.rs
The failure was validated through LiteLLM 1.95.0 against Azure OpenAI.
LiteLLM forwards the nested namespace description unchanged.
Transport does not appear to be the root cause: the invalid payload is produced
by Responses Lite serialization and can affect HTTP or WebSocket transports.
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I don't understand why such a simple issue is taking this long to fix. It's quite frustrating.😡
Pinpointed: the empty string is deliberate and one function deep.
default_namespace_descriptionspecial-cases the default namespace to returnString::new()— every other namespace gets "Tools in the {name} namespace." (https://github.com/openai/codex/blob/1f41cc5d92/codex-rs/tools/src/responses_api.rs#L64-L70). OpenAI's backend tolerates the emptydescription; Azure's Responses validator requires it non-empty and requires the field's presence, which is why both your variants 400.Simplest fix is dropping the special case so
functionsalso gets a real sentence — the field is model-visible prose, and a generic "Standard function tools." is strictly more informative than "". If there's a reason the OpenAI backend prefers the empty string for the default namespace (prompt-length golf?), the alternative is making it provider-aware at serialization, but that seems like complexity for no benefit given a two-word description. Either way this is a one-line change plus a fixture update.