`apply_patch` broken for Azure-hosted GPT-4.1 since v0.80.0 (regression from #593 fix)
What version of Codex CLI is running?
0.111.0
What subscription do you have?
Azure
Which model were you using?
gpt-4.1
What platform is your computer?
macOS (M1)
What terminal emulator and version are you using (if applicable)?
iTerm2
What issue are you seeing?
apply_patch broken for Azure-hosted GPT-4.1 since v0.80.0 (regression from #593 fix)
I deployed a gpt-4.1 model on Azure (this is the latest model I have access to because of my company's security profile). This model works fine with codex CLI and the VSCode integration _except_ it can't use the apply_patch tool at all, which means it can't edit files. This makes codex with 4.1 useless. After much back-and-forth with my AI friend helping me debug the issue, I got it working by writing a custom model catalog entry for gpt-4.1 that tells it how to use apply_patch. Here is a more detailed bug report, generated by my AI friend after collecting all the details. I think this is probably related to issue https://github.com/openai/codex/issues/11940.
What version of Codex is running?
0.111.0 (bug introduced in 0.80.0, last working version is 0.79.0)
Which model were you using?
gpt-4.1 hosted on Azure OpenAI
What platform is your computer?
(fill in your platform here)
What steps can reproduce the bug?
- Configure Codex CLI to use GPT-4.1 hosted on Azure (via
model_providerpointed at an Azure OpenAI endpoint). - Ask the agent to edit a file.
- The agent outputs the patch as plain text in its response instead of calling a tool to apply it. The file is never modified.
What is the expected behavior?
The agent should call a tool (either the dedicated apply_patch tool or the shell tool with apply_patch as the command) to edit the file, as it did in v0.2.0 through v0.79.0.
What do you see instead?
The agent writes the patch content directly into its response message. No tool call is made and no file is modified.
Root cause analysis
This is a regression of the fix for #593. The original issue was identical: GPT-4.1 would write patches inline instead of calling the tool. That fix worked from v0.2.0 through v0.79.0 via two mechanisms:
- System prompt injection:
client_common.rscontained logic that conditionally appendedAPPLY_PATCH_TOOL_INSTRUCTIONS(the detailed V4A diff format instructions) to the system prompt whenmodel.needs_special_apply_patch_instructionswas true and no freeformapply_patchtool was present.
- Model family recognition: The
ModelFamilystruct inmodel_family.rsrecognized model slugs starting with"gpt-4.1"and setneeds_special_apply_patch_instructions: true, regardless of whether the model was hosted on OpenAI or Azure.
In v0.80.0, PR #8763 ("Merge Modelfamily into modelinfo", commit 9179c9dea, Jan 7 2026) removed both mechanisms. The commit message explicitly states "Remove logic for adding instructions to apply patch." The ModelFamily concept was merged into ModelInfo, and model metadata is now sourced entirely from the backend /models endpoint (or the bundled models.json).
The problem is that gpt-4.1 is no longer listed in models.json. When an Azure user specifies gpt-4.1 as their model, the slug doesn't match any catalog entry, so model_info_from_slug() returns a fallback ModelInfo with:
base_instructionsset to the genericprompt.md(no detailed apply_patch format instructions)apply_patch_tool_type: None- The
ApplyPatchFreeformfeature flag defaulting tofalse
This means Azure GPT-4.1 users get neither the apply_patch instructions in the system prompt nor an apply_patch tool in the tool list.
Additionally, even if a user manually enables apply_patch_freeform = true in config.toml, the freeform tool uses type: "custom" (a Responses API feature), which Azure's API rejects with "Invalid value: 'custom'". The Function variant of the tool (type: "function") would work on Azure, but there is no config option to select it — apply_patch_tool_type is only settable via ModelInfo from the backend catalog.
Three compounding issues
- No apply_patch instructions in system prompt — the fallback
model_info_from_slug()uses the genericprompt.mdwhich has only a brief passing reference toapply_patch, not the detailed V4A format instructions the model needs.
- No apply_patch tool registered —
apply_patch_tool_typedefaults toNonein the fallback, andApplyPatchFreeformdefaults tofalse, so no tool is added.
- No config path to the Function tool variant — even if a user forces the freeform tool on via config, Azure rejects
type: "custom". TheFunctionvariant (standard function calling) works on Azure but can only be selected viaModelInfo.apply_patch_tool_type, which isn't user-configurable.
Workaround
The model_catalog_json config option can be used to provide a custom catalog file that includes a gpt-4.1 entry with "apply_patch_tool_type": "function" and the full apply_patch instructions baked into base_instructions. This bypasses the fallback entirely:
# ~/.codex/config.toml
model_catalog_json = "/path/to/custom-catalog.json"
Where custom-catalog.json contains a gpt-4.1 model entry with "apply_patch_tool_type": "function" and "base_instructions" set to the contents of prompt_with_apply_patch_instructions.md.
Note that model_catalog_json replaces the bundled catalog rather than merging with it, so all other model definitions are lost. This is acceptable if only using gpt-4.1, but problematic if switching between models.
Suggested fixes
Any of the following would resolve this (not mutually exclusive):
- Add
gpt-4.1back tomodels.jsonwith"apply_patch_tool_type": "function"and the full instructions inbase_instructions. This is the simplest fix and mirrors how other models are configured.
- Make
apply_patch_tool_typeuser-configurable inconfig.toml(e.g.,apply_patch_tool_type = "function"). This would let users on non-OpenAI providers select the Function variant that works with standard function calling APIs.
- Improve the fallback in
model_info_from_slug()to recognize known model families (gpt-4.1, gpt-4o, gpt-3.5, etc.) and set appropriate defaults forapply_patch_tool_typeandbase_instructions, similar to how the oldModelFamily::find_family_for_model()worked.
- Make
model_catalog_jsonmerge with the bundled catalog instead of replacing it, so users can add entries for their custom/Azure models without losing the built-in model definitions.
Version bisection
| Version | Status |
|---------|--------|
| v0.2.0 | Working |
| v0.55.0 | Working |
| v0.65.0 | Working |
| v0.72.0 | Working |
| v0.76.0 | Working |
| v0.78.0 | Working |
| v0.79.0 | Working (last good) |
| v0.80.0 | Broken (first bad — PR #8763) |
| v0.111.0 | Broken |
Additional information
The prompt_with_apply_patch_instructions.md file that ships alongside prompt.md in the repo is only referenced in tests — it is never loaded by production code. It appears to be a test fixture verifying that certain model slugs in models.json have the correct instructions, but it's not used as a fallback for unknown models.
What steps can reproduce the bug?
See above
What is the expected behavior?
See above
Additional information
See above
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗