Repository navigation
model_tokens leaks to OpenAI client on plain llm config path (TypeError: unexpected keyword argument 'model_tokens') #1099
Description
Describe the bug
When using an OpenAI-compatible provider via plain llm config (api_key + model + base_url) and specifying model_tokens, the request fails because model_tokens is forwarded to the OpenAI client and ends up as an API request parameter:
TypeError: Completions.create() got an unexpected keyword argument 'model_tokens'. Did you mean 'max_tokens'?
model_tokens is meant to be consumed by ScrapeGraphAI (to size chunking / context), not passed through to the model client.
Root cause
In scrapegraphai/graphs/abstract_graph.py, _create_llm() reads model_tokens but never pops it out of llm_params on the standard path:
if llm_params.get("model_tokens", None) is None:
...
self.model_token = 8192
else:
self.model_token = llm_params["model_tokens"] # read, but NOT poppedllm_params (still containing model_tokens) is then splatted straight into init_chat_model(**llm_params):
For a ChatOpenAI client the unknown model_tokens key is treated as a model kwarg and sent to the chat-completions API, which rejects it.
Note the model_instance path (L148-L153) is unaffected because it reads model_tokens and returns early, so the key never reaches a client — which is why the documented model_instance workaround works.
To reproduce
from scrapegraphai.graphs import SmartScraperGraph
graph_config = {
"llm": {
"api_key": "<key>",
"model": "openai/gpt-4o-mini", # any openai-compatible model
"base_url": "https://<any-openai-compatible-endpoint>/v1",
"model_tokens": 128000, # <-- triggers the bug
},
}
SmartScraperGraph(
prompt="Summarize this page",
source="https://example.com",
config=graph_config,
).run()Result: TypeError: Completions.create() got an unexpected keyword argument 'model_tokens'.
Expected behavior
model_tokens should be consumed by ScrapeGraphAI and not forwarded to the underlying model client, regardless of whether the LLM is created from plain config or from a model_instance.
Suggested fix
Pop model_tokens when reading it so it isn't forwarded:
if llm_params.get("model_tokens", None) is None:
try:
self.model_token = models_tokens[llm_params["model_provider"]][llm_params["model"]]
except KeyError:
logger.warning(...)
self.model_token = 8192
else:
self.model_token = llm_params["model_tokens"]
llm_params.pop("model_tokens", None) # <-- ensure it never reaches the clientWorkaround
Build the client yourself and pass it via model_instance, which consumes model_tokens and returns before it can leak:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="...", api_key="...", base_url="...")
graph_config = {"llm": {"model_instance": llm, "model_tokens": 128000}}Environment
- scrapegraphai: 2.1.4
- Python: 3.13.5
- OS: macOS (arm64)
- Provider: OpenAI-compatible endpoint (Cloudflare AI Gateway
/compat), reproducible with any OpenAI-compatiblebase_url.
Activity
dosubot commentedon Jul 8, 2026
Hi @dylanpfirn! I'm Dosu and I'm helping the ScrapeGraphAI, Inc team.
Your analysis is spot-on. I can confirm that
model_tokensis never popped fromllm_paramson the standardinit_chat_modelpath [1]. Onlyrate_limit,temperature(conditionally for Bedrock), andmodel_provider(for special providers) are explicitly removed before the params are splatted into the client constructor.Interestingly, PR #1084 (Atlas Cloud provider integration) already identified and applied exactly the fix pattern you suggest —
llm_params.pop("model_tokens", None)before provider instantiation — but only for that specific provider path [2]. It was not retroactively applied to the generalinit_chat_modelpath, which is why the bug persists for plain OpenAI-compatible configs.Your suggested fix (adding
llm_params.pop("model_tokens", None)right after reading the value around line 222) is the correct and minimal approach, and is consistent with the pattern already established in the codebase.To reply, just mention @dosu.
Docs are dead. Just use Dosu.
rehan243 commentedon Jul 8, 2026
Ran into something similar with LangChain's
ChatOpenAIwrapper, where I was passing custom kwargs that ended up getting sent to the OpenAI API. The error messageTypeError: Completions.create() got an unexpected keyword argument 'model_tokens'is super familiar - that's exactly what I got when I accidentally passedmax_retriesas a model kwarg. I've found that it's usually a good idea to explicitly pop out any kwargs that are meant for internal consumption, likemodel_tokenshere, before splatting the rest into the client init. In this case, it's clear thatmodel_tokensis being read but not removed fromllm_paramsbefore being passed toinit_chat_model. I think adding a simplellm_params.pop('model_tokens', None)after reading the value should fix the issue. I've seen this pattern work well with other libraries like Hugging Face Transformers, where you need to separate out config values meant for the model from those meant for your own logic.github-actions commentedon Jul 8, 2026
🎉 This issue has been resolved in version 2.1.5 🎉
The release is available on:
v2.1.5Your semantic-release bot 📦🚀
github-actions commentedon Aug 19, 2026
🎉 This issue has been resolved in version 2.2.0-beta.6 🎉
The release is available on:
v2.2.0-beta.6Your semantic-release bot 📦🚀