Skip to content

fix: avoid mutating codex output schema input#3385

Open
ioleksiuk wants to merge 1 commit into
openai:mainfrom
ioleksiuk:fix/avoid-mutating-codex-output-schema
Open

fix: avoid mutating codex output schema input#3385
ioleksiuk wants to merge 1 commit into
openai:mainfrom
ioleksiuk:fix/avoid-mutating-codex-output-schema

Conversation

@ioleksiuk
Copy link
Copy Markdown
Contributor

Summary

Mirror the MCP fix in #3134 (and the `FunctionTool` fix in #3382) for the Codex `output_schema` path. `_resolve_output_schema` in `src/agents/extensions/experimental/codex/codex_tool.py:696-700` does `schema = dict(option)`, which is only a shallow copy — nested user dicts (e.g. entries in `option["properties"]`) are the same identity as the caller's. `ensure_strict_json_schema` (documented as mutating its input at `src/agents/strict_schema.py:20`) then mutates those nested dicts in place, leaking strict-mode side effects like `additionalProperties: false` and `required: [...]` back into the caller's stored schema.

```python

nested = {"type": "object", "properties": {"y": {"type": "string"}}}
option = {"type": "object", "properties": {"inner": nested}}
_resolve_output_schema(option)
nested
{'type': 'object', 'properties': {'y': {'type': 'string'}},
'additionalProperties': False, 'required': ['y']}
```

Switch to `copy.deepcopy(dict(option))` so the strict conversion only mutates the local copy, matching the precedent established by #3134 in MCP and #3382 in `FunctionTool`.

Test plan

  • New regression test `test_codex_tool_resolve_output_schema_does_not_mutate_input` verifying both the top-level option dict and a nested object schema remain unmodified after `_resolve_output_schema` returns, and that the returned dict's nested entry is a fresh copy.
  • `uv run pytest tests/extensions/experiemental/codex/test_codex_tool.py -k resolve_output_schema` — 3 passed.
  • `uv run ruff check` on the touched files — All checks passed.

Issue number

N/A — found while auditing for the same mutation-aliasing pattern that #3134 and #3382 fixed.

Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation (no doc changes needed)
  • I've run `make lint` and `make format`
  • I've made sure tests pass

Mirror the MCP fix in openai#3134 (and the FunctionTool fix in openai#3382) for the
Codex output_schema path. `_resolve_output_schema` currently does
`schema = dict(option)`, which is only a shallow copy — nested user
dicts (e.g. each entry in `option["properties"]`) are the same identity
as the caller's. `ensure_strict_json_schema` then mutates those nested
dicts in place (it is documented as mutating its input), leaking
strict-mode side effects like `additionalProperties: false` and
`required: [...]` back into the caller's stored schema.

Switch to `copy.deepcopy(dict(option))` so the strict conversion only
mutates the local copy, matching the precedent established by openai#3134.
@seratch
Copy link
Copy Markdown
Member

seratch commented May 13, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants