oobabooga/textgen · error · InvalidRequestError
max_tokens must be greater than 0.
Error message
max_tokens must be greater than 0.
What it means
In the chat completions path, after process_parameters maps 'max_tokens' to 'max_new_tokens', a value that is set and <= 0 raises InvalidRequestError (400, param='max_tokens'). Note this is stricter than the text-completions path (errors 13/14): the chat endpoint does not allow 0 even for logprob-only requests; None means auto (512 + auto_max_new_tokens).
Source
Thrown at modules/api/completions.py:581
generate_params.update({
'mode': body['mode'],
'name1': name1,
'name2': name2,
'context': context,
'greeting': greeting,
'user_bio': user_bio,
'instruction_template_str': instruction_template_str,
'custom_system_message': custom_system_message,
'chat_template_str': chat_template_str,
'chat-instruct_command': chat_instruct_command,
'tools': tools,
'history': history,
'stream': stream
})
max_tokens = generate_params['max_new_tokens']
if max_tokens is not None and max_tokens <= 0:
raise InvalidRequestError(message="max_tokens must be greater than 0.", param="max_tokens")
if max_tokens is None:
generate_params['max_new_tokens'] = 512
generate_params['auto_max_new_tokens'] = True
requested_model = generate_params.pop('model')
logprob_proc = generate_params.pop('logprob_proc', None)
if logprob_proc:
logprob_proc.token_alternatives_history.clear()
chat_logprobs_offset = [0] # mutable for closure access in streaming
def chat_streaming_chunk(content=None, chunk_tool_calls=None, include_role=False, reasoning_content=None):
# begin streaming
delta = {}
if include_role:
delta['role'] = 'assistant'
delta['refusal'] = None
if content is not None:View on GitHub (pinned to ed888c71f2)
Solutions
- Send a positive integer: {"max_tokens": 512}.
- To request auto sizing, omit 'max_tokens' entirely (server then defaults to 512 + auto_max_new_tokens).
- Clamp computed budgets client-side: max(1, budget - used) or drop the field when <= 0.
- If you wanted a 0-token logprob-only call, use the /v1/completions endpoint with logprobs instead.
Example fix
# before
body = {"model": m, "messages": msgs, "max_tokens": max(0, budget - used)}
# after
body = {"model": m, "messages": msgs}
if budget - used > 0:
body["max_tokens"] = budget - used Defensive patterns
Strategy: validation
Validate before calling
def resolve_max_tokens(remaining: int | None):
if remaining is None or remaining <= 0:
return None # omit -> server auto sizing (512 + auto_max_new_tokens)
return remaining
body = {'model': m, 'messages': msgs}
mt = resolve_max_tokens(budget - used)
if mt is not None:
body['max_tokens'] = mt Type guard
def is_valid_chat_max_tokens(v) -> bool:
return v is None or (isinstance(v, int) and not isinstance(v, bool) and v > 0) Try / catch
try:
resp = client.chat.completions.create(model=m, messages=msgs, max_tokens=mt)
except openai.BadRequestError as e:
if 'max_tokens must be greater than 0' in str(e):
resp = client.chat.completions.create(model=m, messages=msgs) # omit: auto
else:
raise Prevention
- Clamp computed budgets with max(1, n) or drop the field when <= 0.
- Remember chat endpoint rejects 0 even with logprobs; only /v1/completions allows the 0+logprobs mode.
- Use None/omission for auto sizing, never -1.
When it happens
Trigger: POST /v1/chat/completions with {"max_tokens": 0} or a negative value. Compute-bound code doing max_tokens = budget - used and sending it when the budget is exhausted (0 or negative) is a classic trigger.
Common situations: Token-budget managers passing 0 when the context is full; sending -1 as an 'unlimited' convention from other inference servers (this backend treats None, not -1, as auto); test payloads with 0.
Related errors
- functions is not supported.
- function_call is not supported.
- messages is required
- messages: missing role
- role: function is not supported.
AI-assisted analysis of oobabooga/textgen@ed888c71f2 (2026-08-15).
Data as JSON: /api/errors/6428d334caa0295c.
Report an issue: GitHub.