oobabooga/textgen · error · InvalidRequestError

messages: missing role

Error message

messages: missing role

What it means

Each element of the 'messages' array is validated to contain a 'role' key before processing. A message dict without 'role' raises InvalidRequestError (400, param='messages'). Roles are needed to apply the chat template correctly.

Source

Thrown at modules/api/completions.py:498

    if body.get('function_call', ''):
        raise InvalidRequestError(message="function_call is not supported.", param='function_call')

    if 'messages' not in body:
        raise InvalidRequestError(message="messages is required", param='messages')

    tools = None
    if 'tools' in body and body['tools'] is not None and isinstance(body['tools'], list) and body['tools']:
        tools = validateTools(body['tools'])  # raises InvalidRequestError if validation fails

    tool_choice = body.get('tool_choice', None)
    if tool_choice == "none":
        tools = None  # Disable tool detection entirely

    messages = body['messages']
    for m in messages:
        if 'role' not in m:
            raise InvalidRequestError(message="messages: missing role", param='messages')
        elif m['role'] == 'function':
            raise InvalidRequestError(message="role: function is not supported.", param='messages')

        # Handle multimodal content validation
        content = m.get('content')
        if content is None:
            # OpenAI allows content: null on assistant messages when tool_calls is present
            if m['role'] == 'assistant' and m.get('tool_calls'):
                m['content'] = ''
            else:
                raise InvalidRequestError(message="messages: missing content", param='messages')

        # Validate multimodal content structure
        if isinstance(content, list):
            for item in content:
                if not isinstance(item, dict) or 'type' not in item:
                    raise InvalidRequestError(message="messages: invalid content item format", param='messages')
                if item['type'] not in ['text', 'image_url']:

View on GitHub (pinned to ed888c71f2)

Solutions

  1. Ensure every message dict has a role: system | user | assistant | tool.
  2. Validate/normalize your messages array client-side before sending (see defense below).
  3. Log the exact payload on 400 to spot which element is malformed.

Example fix

# before
messages = [{"content": "hello"}]

# after
messages = [{"role": "user", "content": "hello"}]
Defensive patterns

Strategy: validation

Validate before calling

def normalize_messages(messages):
    out = []
    for m in messages:
        if 'role' not in m:
            raise ValueError(f"message missing role: {m!r}")
        out.append({'role': m['role'], 'content': m.get('content', '')})
    return out

Type guard

def is_valid_message(m) -> bool:
    return isinstance(m, dict) and isinstance(m.get('role'), str) and m['role'] in {'system', 'user', 'assistant', 'tool'}

Try / catch

try:
    resp = client.chat.completions.create(model=m, messages=msgs)
except openai.BadRequestError as e:
    if 'missing role' in str(e):
        msgs = normalize_messages(msgs)  # or fix the builder and re-raise
    raise

Prevention

When it happens

Trigger: POST /v1/chat/completions where any element of messages lacks 'role', e.g. {"content": "hi"}, or is not a dict-shaped object with role (e.g. sending a bare string element that the framework wraps without a role).

Common situations: Building messages dynamically and forgetting to set the role; sending [{'user': 'text'}] instead of [{'role': 'user', 'content': 'text'}]; template string formatting bugs like '[{"role": "" + role + ""}]'.

Related errors


AI-assisted analysis of oobabooga/textgen@ed888c71f2 (2026-08-15). Data as JSON: /api/errors/fac0e1eac0f25639. Report an issue: GitHub.