0.147.0 regression: Azure Responses rejects empty functions namespace description

Open 💬 26 comments Opened Aug 7, 2026 by jisunchoii
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.147.0

What subscription do you have?

Azure OpenAI through a custom Responses provider (routed through Azure API Management).

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What terminal emulator and version are you using (if applicable)?

VS Code integrated terminal / PowerShell.

Codex doctor report

Not included because the issue is reproducible from the serialized HTTP payload and contains no authentication or connectivity failure.

What issue are you seeing?

Codex CLI 0.147.0 fails before the model can answer when using an Azure OpenAI Responses provider:

{
  "error": {
    "message": "Invalid 'input[0].tools[0].description': empty string. Expected a string with minimum length 1, but got an empty string instead.",
    "type": "invalid_request_error",
    "param": "input[0].tools[0].description",
    "code": "empty_string"
  }
}

The serialized request contains this first input item:

{
  "type": "additional_tools",
  "role": "developer",
  "tools": [
    {
      "type": "namespace",
      "name": "functions",
      "description": "",
      "tools": [
        {
          "type": "custom",
          "name": "exec",
          "description": "Run JavaScript code to orchestrate/compose tool calls..."
        }
      ]
    }
  ]
}

Azure's NamespaceToolParam schema requires description and specifies minLength: 1:
https://learn.microsoft.com/rest/api/microsoft-foundry/azureopenai/responses#openainamespacetoolparam

This is a regression from 0.146.0. With the same provider, model, authentication, and prompt, 0.146.0 sends the exec custom tool directly without the empty functions namespace and succeeds.

Disabling only code_mode_host does not work around the issue in 0.147.0; the empty namespace remains in the serialized request.

What steps can reproduce the bug?

Configure a custom Azure OpenAI Responses provider:

model_provider = "azure"
model = "gpt-5.6-sol"

[model_providers.azure]
name = "Azure OpenAI"
base_url = "https://<azure-or-gateway-endpoint>/openai/v1"
wire_api = "responses"

Then run:

codex exec --ephemeral --skip-git-repo-check "Reply with exactly: OK"

Observed comparison:

  • 0.146.0: succeeds and returns OK.
  • 0.147.0: returns the input[0].tools[0].description validation error above.

I captured the failing 0.147.0 request and replayed it against the same endpoint, changing only:

"description": "Default Codex tools."

The otherwise identical request returned HTTP 200. This confirms the empty namespace description is the direct cause.

The regression appears related to #37022, which grouped default tools under the functions namespace:
https://github.com/openai/codex/pull/37022

What is the expected behavior?

Codex should serialize the default functions namespace with a non-empty description, for example:

"description": "Default Codex tools."

Alternatively, it should avoid the namespace wrapper for providers that do not advertise support for that request shape.

Additional information

Related provider compatibility reports:

  • #31875
  • #31882
  • #32318

This report is narrower: it specifically covers the 0.146.0 to 0.147.0 regression introduced by serializing the new functions namespace with an empty required description.

View original on GitHub ↗

26 Comments

wikcheng · 21 days ago

This happens 100% of the time on 0.147.0 if you're using Azure OpenAI. To fix, I downgraded to 0.146.1.

lql341 · 21 days ago

Independent reproduction on macOS 26.6 (arm64) with codex-cli 0.147.0 and a custom OpenAI-compatible Responses provider. This does not appear to be Windows- or Azure-specific.

The same endpoint, authentication, Responses wire protocol, and model configuration worked with 0.146.1. After upgrading to 0.147.0, the first request fails before model output with the same validation error:

Invalid 'input[0].tools[0].description': empty string. Expected a string with minimum length 1, but got an empty string instead.

There is also a useful model-catalog signal:

  • Applying a compatibility override to only one model makes only that model work.
  • Applying "tool_mode": null and "use_responses_lite": false to every available model makes every model work again.
  • wire_api = "responses", the endpoint, and credentials remain unchanged.

That makes the failure follow the per-model Responses Lite / code-mode metadata rather than authentication or ordinary Responses routing.

Current main still deliberately returns an empty string for the default functions namespace in default_namespace_description(), and responses_lite_preserves_empty_functions_namespace_description asserts that wire value. This seems inconsistent with the earlier rationale in #17946, which established that namespace descriptions need a non-empty fallback because Responses-compatible endpoints reject description: "".

A minimal fix would be to keep the new namespace grouping while giving the default namespace a non-empty fallback, for example:

pub fn default_namespace_description(namespace_name: &str) -> String {
    format!("Tools in the {namespace_name} namespace.")
}

and update the Responses Lite regression test to assert the non-empty description.

I would be happy to prepare the focused code change and tests if a maintainer would like to invite an external PR.

lql341 · 21 days ago
This happens 100% of the time on 0.147.0 if you're using Azure OpenAI. To fix, I downgraded to 0.146.1.

I believe this should be fixed in the Responses request construction rather than through per-model configuration.

### Root cause

In Codex 0.147.0, the Responses Lite path generates an empty description for the default functions namespace:

```rust
pub fn default_namespace_description(namespace_name: &str) -> String {
if namespace_name == DEFAULT_FUNCTION_NAMESPACE {
String::new()
} else {
format!("Tools in the {namespace_name} namespace.")
}
}

This causes Codex to serialize a tool with:

{
"description": ""
}

A Responses-compatible endpoint can reject this request because tool descriptions must be non-empty:

Invalid 'input[0].tools[0].description': empty string.
Expected a string with minimum length 1.

This is provider- and model-independent: any model using this Responses Lite serialization path can be affected.

### Proposed fix

Always generate a non-empty namespace description, including for the default functions namespace:

pub fn default_namespace_description(namespace_name: &str) -> String {
format!("Tools in the {namespace_name} namespace.")
}

Alternatively, the default namespace can return a dedicated description:

pub fn default_namespace_description(namespace_name: &str) -> String {
if namespace_name == DEFAULT_FUNCTION_NAMESPACE {
"Tools in the functions namespace.".to_string()
} else {
format!("Tools in the {namespace_name} namespace.")
}
}

It would also be useful to add a defensive check at the Responses serialization boundary so that Codex never emits a
tool whose description is empty or whitespace-only.

### Regression test

The existing test that expects the default namespace description to remain empty should be changed to expect a non-
empty value.

A request-level regression test should also:

  1. Build a Responses Lite request containing a normal function tool.
  2. Serialize the request.
  3. Assert that every emitted tool description satisfies:

assert!(!description.trim().is_empty());

### Temporary workaround

Disabling the Responses Lite tool path through model metadata avoids the invalid payload:

{
"tool_mode": null,
"use_responses_lite": false
}

However, this must be added to every affected model entry, so it is only a configuration workaround. Fixing the
default namespace description would solve the issue for all models and all OpenAI-compatible Responses providers.

lql341 · 21 days ago

As a temporary workaround, I kept the provider on the Responses API and supplied a custom model catalog:

```toml
wire_api = "responses"
model_catalog_json = "/path/to/model-catalog.json"

In model-catalog.json, I added the following fields to every affected model entry:

{
"tool_mode": null,
"use_responses_lite": false
}

This prevents Codex from using the Responses Lite namespace serialization path that produces the empty tool
description. It does not switch the provider to Chat Completions and tool calling continues to work.

These fields must be added to every selectable model, not only the default model. Otherwise, switching to another
model can trigger the same 400 error again.

This is only a temporary workaround because these model-catalog fields appear to be internal and are not documented as
stable public configuration options.

jgador · 21 days ago

This is the Nth time that they release a tool that's broken.

Hundsmuhlen · 20 days ago

If you're installing over the sh script directly from OpenAI you can easily revert to the previous version. Then when it restarts just skip updates until the next version where it's hopefully fixed - fingers crossed!

CODEX_NON_INTERACTIVE=1 sh -c "$(curl -fsSL https://chatgpt.com/codex/install.sh)" -- --release 0.146.0

Or equivalently, with the env var:

CODEX_RELEASE=0.146.0 sh -c "$(curl -fsSL https://chatgpt.com/codex/install.sh)"

etraut-openai contributor · 20 days ago

If you haven't already done so, please report the problem to Azure. It sounds like their responses endpoint implementation is out of date. They periodically sync their implementation with OpenAI's.

emerzon · 20 days ago

Duplicate with #37425

mjstealey · 20 days ago

Additional data point for whoever picks up the patch: omitting the field is not a valid fix.

The obvious patch — #[serde(skip_serializing_if = "String::is_empty")] on the namespace description — would trade one 400 for another. description is required on NamespaceToolParam, so dropping it fails validation too.

Verified against a live Azure-backed Responses endpoint, same minimal payload each time, only input[0].tools[0].description varying:

| description | Result |
| --- | --- |
| "" (what 0.147.0 sends) | 400 empty_string |
| key omitted | 400 missing_required_parameter |
| any non-empty string | 200 OK |

So default_namespace_description() needs to return a non-empty string for DEFAULT_FUNCTION_NAMESPACE — the existing format!("Tools in the {namespace_name} namespace.") branch works as-is.

Minimal repro, no Codex required:

curl -s https://<responses-endpoint>/v1/responses \
  -H 'Content-Type: application/json' -H "Authorization: Bearer $KEY" -d '{
  "model": "gpt-5.6-sol",
  "input": [
    {"type": "additional_tools", "role": "developer", "tools": [
      {"type": "namespace", "name": "functions", "description": "", "tools": [
        {"type": "function", "name": "ping", "description": "Ping.",
         "parameters": {"type":"object","properties":{},"additionalProperties":false}, "strict": false}
      ]}
    ]},
    {"type": "message", "role": "user", "content": [{"type": "input_text", "text": "say OK"}]}
  ]}'

Change "description": "" to any non-empty string and the identical request returns 200.

For completeness, the captured payload diff on macOS 15 (arm64), same config, provider and prompt, model gpt-5.6-sol, captured by pointing base_url at a local sink:

0.146.1 and 0.145.0input[0] (additional_tools) carries four tools flat, all descriptions populated:

custom exec | function wait | function request_user_input | namespace collaboration

0.147.0 — the same tools are wrapped in a functions namespace whose description is empty:

namespace functions      description=""      <- rejected
  |- custom   exec
  |- function wait
  |- function request_user_input
namespace collaboration  description="..."   (ok)

That empty string is the only one in the entire ~63 KB request body, so the blast radius of the fix is a single field.

DanjalZockt · 18 days ago

Confirming @lql341's analysis and proposed fix. I applied the same minimal change locally and updated the focused tool serialization and Responses Lite request tests. Both pass:

just test -p codex-tools responses_lite_sets_non_empty_functions_namespace_description
just test -p codex-core responses_lite_uses_input_items_for_instructions_and_tools

I also built the patched CLI and tested it against a live Azure OpenAI Responses endpoint using gpt-5.6-sol. With the same provider configuration and prompt, the official 0.147.0 binary fails with empty_string, while the patched binary completes successfully and returns OK.

I have not opened a PR because the repository requires an explicit invitation. If useful, may I be invited to submit the focused patch, or would the maintainers prefer to apply it internally?

fff7d1bc · 18 days ago
diff --git a/codex-rs/tools/src/responses_api.rs b/codex-rs/tools/src/responses_api.rs
index e450dcf35f..52104a0eb5 100644
--- a/codex-rs/tools/src/responses_api.rs
+++ b/codex-rs/tools/src/responses_api.rs
@@ -4,7 +4,6 @@ use crate::ToolName;
 use crate::parse_agent_plugin_mcp_tool;
 use crate::parse_dynamic_tool;
 use crate::parse_mcp_tool;
-use codex_protocol::DEFAULT_FUNCTION_NAMESPACE;
 use codex_protocol::dynamic_tools::DynamicToolFunctionSpec;
 use serde::Deserialize;
 use serde::Serialize;
@@ -62,11 +61,7 @@ pub struct ResponsesApiNamespace {
 }

 pub fn default_namespace_description(namespace_name: &str) -> String {
-    if namespace_name == DEFAULT_FUNCTION_NAMESPACE {
-        String::new()
-    } else {
-        format!("Tools in the {namespace_name} namespace.")
-    }
+    format!("Tools in the {namespace_name} namespace.")
 }

 #[derive(Debug, Clone, Serialize, PartialEq)]

against rust 0.147.0 tag fixed it for me.

LifeBringer · 17 days ago

Still present in 0.148.0-alpha.6 (published 2026-08-10), so the fix has not landed on the 0.148 line either.

Captured the serialized request from the alpha binary against a local capture endpoint. macOS 26.5 arm64, custom Microsoft Foundry Responses provider, gpt-5.6-sol:

codex 0.148.0-alpha.6 | input[0].type = additional_tools
   namespace functions       description=''
   namespace collaboration   description='Tools for spawning and managing sub-agents.'

default_namespace_description() is unchanged, so anyone on a non-ChatGPT Responses backend will hit this again on the next stable release unless the one-line fix in this thread lands first.

Scope, from the same endpoint

Affected: gpt-5.6-sol, gpt-5.6-luna, gpt-5.6-terra. All three serialize tools as an additional_tools input item with the empty functions namespace.

Unaffected: gpt-5.5, gpt-5.4, gpt-5.3-codex, gpt-5.2-codex, gpt-5.1-codex-max. These send a standard top-level tools array with no namespaces at all.

Exactly one empty description per request, always input[0].tools[0].

Workaround: patch in flight instead of downgrading

I pointed the provider base_url at a localhost shim that fills any empty description and forwards everything else untouched:

[model_providers.foundry]
base_url = "http://127.0.0.1:8900/openai/v1"
wire_api = "responses"
def fill_empty_descriptions(node, counter):
    if isinstance(node, dict):
        if node.get("description") == "":
            node["description"] = node.get("name") or "(no description)"
            counter[0] += 1
        for value in node.values():
            fill_empty_descriptions(value, counter)
    elif isinstance(node, list):
        for value in node:
            fill_empty_descriptions(value, counter)

The only non-obvious requirement is that the shim has to stream the SSE response through as it arrives rather than buffering it, otherwise output arrives in one lump at the end of the turn. Verified end to end on 0.147.0 with multi-turn shell tool calls at model_reasoning_effort = "max".

Why not the other two workarounds

Downgrading to 0.146.1 gives up a release, and with 0.148 alphas still affected it is an open-ended hold rather than a short one.

model_catalog_json with use_responses_lite: false works by disabling Responses Lite, which costs the code-mode exec tool. For 5.6 specifically that is much of the reason to be on the model. It also has to be repeated for every selectable model, and those fields are undocumented internals.

The shim keeps 5.6 behavior fully intact, needs no change to Codex, and is self-retiring: it logs how many descriptions it patched per request, so patched 0 on every request is the signal that the upstream fix has landed and it can be deleted.

Happy to keep testing alphas against a live Foundry endpoint if that is useful to whoever picks this up.

LifeBringer · 17 days ago

Follow-up with schema evidence, since it explains why this only reproduces on Azure and suggests both sides have something to change.

Sending "description": "" is valid against OpenAI's own published schema. From openai/openai-openapi, component NamespaceToolParam (identical in BetaNamespaceToolParam):

name:
  type: string
  minLength: 1          # explicitly constrained
  description: The namespace name used in tool calls (for example, `crm`).
description:
  type: string          # no minLength
  description: A description of the namespace shown to the model.
required: [type, name, description, tools]

description is required but unconstrained in length, while name immediately above it carries an explicit minLength: 1. So 0.147.0 is emitting a technically spec-conformant request.

Azure adds the constraint. Their published spec is derived from the same source and is otherwise identical, including the doc strings, the required list, minLength: 1 on name, and minItems: 1 on tools. It differs by exactly one line (microsoft-foundry-openapi3.yaml, v1, L62594-62597):

description:
  type: string
  minLength: 1          # <-- not upstream
  description: A description of the namespace shown to the model.

I have filed that against the spec as Azure/azure-rest-api-specs#45388.

That makes @etraut-openai's suggestion to report this to Azure the right call, and I have done so. Two notes for whoever picks this up here, though:

  1. It is a divergence in validation strictness rather than an out-of-date implementation. Foundry implements additional_tools and namespace correctly, and the same request returns 200 with any non-empty description. Only this one field differs.
  2. The Azure-side fix will not help anyone for a while, since a spec change still has to propagate to the deployed service. The one-line change to default_namespace_description() proposed earlier in this thread unblocks every affected user immediately, and sending a real description is better for the model regardless of which schema is treated as authoritative.

Confirming again that this still reproduces on 0.148.0-alpha.6.

jacobmischka · 16 days ago

@LifeBringer are you willing to post that full shim you're using?

ravindren-sm · 16 days ago

Independent reproduction confirming the root cause described above (functions namespace description empty string) against a custom OpenAI-compatible Responses provider proxying to an internal Azure OpenAI Foundry deployment.

Environment: Windows, codex-cli 0.147.0, custom model_provider (wire_api = "responses"), model aliased to the gpt-5.6-terra catalog entry.

Error observed (deterministic, 100% reproducible, same on every retry):

"message": "Invalid 'input[0].tools[0].description': empty string. Expected a string with minimum length 1, but got an empty string instead.",
"type": "invalid_request_error", "param": "input[0].tools[0].description", "code": "empty_string"

Captured the actual request payload via a local logging reverse proxy (custom model_provider pointed at 127.0.0.1) to confirm tools[0] is exactly the "namespace"/"functions" wrapper object with description: "", matching what's described above.

One additional data point nobody's posted yet: tried codex exec --disable code_mode_host --disable code_mode as a hoped-for client-side workaround. This does not avoid the bug — Codex prints Code Mode is unavailable because code-mode host is disabled. Code mode will fail closed; enable features.code_mode_host and install codex-code-mode-host, but still serializes and sends the exact same empty-description functions namespace object regardless of the feature flag state. So disabling the feature only breaks Code Mode's own tool execution, without avoiding the malformed request.

Workaround that does work (per the tool_mode/use_responses_lite fix posted above): pulled the built-in catalog via codex debug models, set "tool_mode": null, "use_responses_lite": false on the three affected gpt-5.6-* entries, saved as a custom file, and pointed model_catalog_json at it in config.toml. Confirmed working end-to-end on a real request that previously failed 100% of the time.

+1 on the proposed default_namespace_description fix — happy to test a build if one gets cut.

BOPOHA · 15 days ago

here is a workaround for downgrading the codex cli version, the key is CODEX_RELEASE=0.146.1 :

$ curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 CODEX_RELEASE=0.146.1 sh
==> Updating Codex CLI from 0.147.0 to 0.146.1
==> Detected platform: Linux (x64)
==> Resolved version: 0.146.1
==> /home/user/.local/bin is already on PATH
==> Current terminal: codex
==> Future terminals: open a new terminal and run: codex
Codex CLI 0.146.1 installed successfully.
naipi11 · 9 days ago

If Azure / Foundry Responses rejects 0.147.0 with empty functions namespace description, pin back to 0.146.1. That build does not wrap exec in an empty namespace.

Method:

  1. Reinstall CLI 0.146.1 with the official installer pin: CODEX_NON_INTERACTIVE=1 CODEX_RELEASE=0.146.1 against https://chatgpt.com/codex/install.sh (Windows: npm install -g @openai/codex@0.146.1).
  2. Confirm codex --version reports 0.146.1.
  3. Retry the same Azure Responses profile.
  4. Stay on 0.146.1 until a 0.147.x note says the namespace description is no longer an empty string.

Evidence: 0.147.0 serializes tools[0] as a functions namespace with "description": "". Azure's NamespaceToolParam requires minLength 1. Thread confirmations include the official installer pin to 0.146.1.

Independent community workaround; not an official OpenAI fix.

seabrig · 9 days ago

is there a workaround for the chatgpt app? I'm running into the same issue there, but don't see a way to downgrade app versions

gisle · 9 days ago

I got codex cli 0.148.0 today. The problem is still there.

SLin-code · 9 days ago

functions namespace is serialized with "description": "", which strict Responses API backends (Azure) reject with 400

Status: still reproducing on main @ f5a3dc5 and on 0.148.0-alpha.15.

TL;DR

The default functions namespace is special-cased to an empty description, and the field is a non-optional String with no skip attribute — so every request carries "description": "", which Azure-backed Responses endpoints reject as empty_string.

Root cause

<!-- codex-rs/tools/src/responses_api.rs:64-70 -->

// codex-rs/tools/src/responses_api.rs:64-70
pub fn default_namespace_description(namespace_name: &str) -> String {
    if namespace_name == DEFAULT_FUNCTION_NAMESPACE {
        String::new()          // <-- "functions" is special-cased to an empty string
    } else {
        format!("Tools in the {namespace_name} namespace.")
    }
}

Every other namespace (collaboration, web, skills, memory, image_gen) gets a real description from this same helper; only functions gets "".

Why the empty value reaches the wire
// codex-rs/tools/src/responses_api.rs:57-62
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct ResponsesApiNamespace {
    pub name: String,
    pub description: String,   // String, not Option<String>, and no skip_serializing_if
    pub tools: Vec<ResponsesApiNamespaceTool>,
}

So the empty string is always serialized rather than omitted.

Observed request payload

Captured with a local forwarding proxy. input[0] is an additional_tools item:

{
  "type": "additional_tools",
  "role": "developer",
  "tools": [
    { "type": "namespace", "name": "functions",     "description": "",                                      "tools": [3 tools] },
    { "type": "namespace", "name": "collaboration", "description": "Tools in the collaboration namespace.", "tools": [6 tools] }
  ]
}

All 9 inner tools have proper descriptions (exec is 10,495 chars) — only the outer functions container is empty.

Error returned by the gateway:

Invalid 'input[0].tools[0].description': empty string.
Expected a string with minimum length 1, but got an empty string instead.
param: input[0].tools[0].description
code:  empty_string
Suggested fix

Option A — drop the special case (smallest diff):

--- a/codex-rs/tools/src/responses_api.rs
+++ b/codex-rs/tools/src/responses_api.rs
 pub fn default_namespace_description(namespace_name: &str) -> String {
-    if namespace_name == DEFAULT_FUNCTION_NAMESPACE {
-        String::new()
-    } else {
-        format!("Tools in the {namespace_name} namespace.")
-    }
+    format!("Tools in the {namespace_name} namespace.")
 }

Two things suggest this doesn't break semantics:

  1. The downstream consumer already guards on a non-empty description, i.e. this code path anticipates a non-empty value:

``rust
// codex-rs/tools/src/tool_spec.rs:118-120
ToolSpec::Namespace(namespace) if namespace.name == DEFAULT_FUNCTION_NAMESPACE => {
if !namespace.description.trim().is_empty() {
functions.description = namespace.description.clone();
}
``

  1. Every other namespace already uses exactly this generic format.

Option B — make the field optional, if the empty description is deliberate (i.e. you don't want filler text for the default namespace):

--- a/codex-rs/tools/src/responses_api.rs
+++ b/codex-rs/tools/src/responses_api.rs
 pub struct ResponsesApiNamespace {
     pub name: String,
-    pub description: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub description: Option<String>,
     pub tools: Vec<ResponsesApiNamespaceTool>,
 }

This omits the key instead of sending an empty value, preserving current prompt semantics for existing backends.

Tests that would need updating either way:

  • codex-rs/tools/src/tool_spec_tests.rs:235assert_eq!(tools[0]["description"], "");
  • codex-rs/core/tests/suite/responses_lite.rs:144assert_eq!(functions_namespaces[0]["description"], "");

<details>
<summary><b>No client-side workaround exists — 16 configurations verified against a mock server</b></summary>

Verified by capturing the outgoing request body against a local mock server (zero API cost):

| Attempted workaround | Result |
| --- | --- |
| code_mode / code_mode_host / code_mode_only = false | empty description still sent |
| collaboration_modes = false | still sent |
| multi_agent / multi_agent_v2 = false | still sent |
| include_collaboration_mode_instructions = false | still sent |
| tool_search / deferred_tool_world_state = false | still sent |
| js_repl / js_repl_tools_only = false | still sent |
| experimental_supported_tools = [] | still sent |
| [tools.update_plan] enabled = false | still sent |
| All of the above combined | still sent |
| Non-GPT-5.6 model (gpt-4.1) | still sent |
| Empty CODEX_HOME (no plugins/skills/MCP) | still sent |

The functions namespace container is emitted unconditionally and is not gated behind any feature flag.

</details>

Interacting constraint (worth flagging separately)

On the same gateway, dropping the x-context-provider: Azure header routes to a different backend that accepts the empty description but rejects reasoning.context:

unknown field in strict mode: 'reasoning.context'

Codex sends reasoning: { effort, context } unconditionally for GPT-5.6-family models, and removing model_reasoning_effort from config does not stop it. So neither route is usable from the client side today. Happy to file that as a separate issue if you'd prefer.

naipi11 · 8 days ago

The CLI pin does not carry over to the ChatGPT desktop app. I do not know of a supported app-version downgrade or a confirmed app-side switch that removes this empty namespace.

For now:

  1. Keep the Azure/custom Responses profile on CLI 0.146.1 for work that must use that provider.
  2. Use the desktop app only for a routing path that does not hit the strict Azure/custom endpoint, if that is available in your setup.
  3. Verify the boundary from the sanitized 400 response: if it still names tools[0].description as an empty string, the bundled client still needs the upstream serialization fix.

Limitation: disabling only code_mode_host was already reported not to remove the empty namespace, so this is a CLI fallback rather than a desktop-app fix.

gisle · 7 days ago

Today it seems that Azure have changed something. Codex >= 0.147.0 is now compatible with it.

rx4747 · 7 days ago
Today it seems that Azure have changed something. Codex >= 0.147.0 is now compatible with it.

Have u updated to 0.149?

Kinda too scared it will explode

nikzart · 7 days ago
Today it seems that Azure have changed something. Codex >= 0.147.0 is now compatible with it.

is this fixed now?

ZeppLu · 7 days ago

Confirmed fixed using 0.149 on Linux

naipi11 · 6 days ago

Update: several users now report that Azure/Foundry compatibility is restored in Codex 0.149, including a confirmation on Linux.

If you use the affected Azure Responses profile:

  1. Update to 0.149.
  2. Confirm codex --version.
  3. Run the same minimal request against the same provider.
  4. Verify that the empty functions namespace description error is gone.

The earlier 0.146.1 pin is now only a fallback for users who still reproduce the error; it should not be treated as the preferred path when 0.149 works.