sgl-project/sglang · error · ValueError

The messages should be a list of dict.

Error message

The messages should be a list of dict.

What it means

generate_chat_conv expects request.messages to be a list of message objects (ChatCompletionMessage), not a plain string. If a str is passed, it raises this ValueError before iterating roles. This mirrors the OpenAI API where 'messages' is an array of dicts, not a string.

Source

Thrown at python/sglang/srt/parser/conversation.py:629

        roles=conv.roles,
        messages=list(conv.messages),  # prevent in-place modification
        offset=conv.offset,
        sep_style=SeparatorStyle(conv.sep_style),
        sep=conv.sep,
        sep2=conv.sep2,
        stop_str=conv.stop_str,
        image_data=[],
        video_data=[],
        audio_data=[],
        modalities=[],
        image_token=conv.image_token,
        audio_token=conv.audio_token,
        video_token=conv.video_token,
        image_token_at_prefix=conv.image_token_at_prefix,
    )

    if isinstance(request.messages, str):
        raise ValueError("The messages should be a list of dict.")
    for message in request.messages:
        msg_role = message.role
        if msg_role == "system":
            if isinstance(message.content, str):
                conv.system_message = message.content
            elif isinstance(message.content, list):
                if (
                    len(message.content) != 1
                    or getattr(message.content[0], "type", None) != "text"
                ):
                    raise ValueError("The system message should be a single text.")
                else:
                    conv.system_message = getattr(message.content[0], "text", "")
        elif msg_role == "user":
            # Handle the various types of Chat Request content types here.
            if isinstance(message.content, str):
                conv.append_message(conv.roles[0], message.content)
            else:

View on GitHub (pinned to 0132848349)

Solutions

  1. Pass a list of message dicts: messages=[{"role":"user","content":"..."}]
  2. Use the completions API (text prompt) instead if you have a single string

Example fix

# before
llm.chat("Hello")  # or messages="Hello"
# after
llm.chat([{"role":"user","content":"Hello"}])
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(messages, list) and all(isinstance(m, dict) for m in messages)

Type guard

def is_valid_messages(msgs) -> bool:
    return isinstance(msgs, list) and all(
        isinstance(m, dict) and m.get("role") in {"system","user","assistant"} for m in msgs
    )

Try / catch

try: resp = llm.chat(msgs)
except ValueError as e: if "list of dict" in str(e): fix payload

Prevention

When it happens

Trigger: Calling the chat completion path with GenerateChatReqInput(messages="Hello") instead of messages=[{"role":"user","content":"Hello"}].

Common situations: Treating the chat endpoint like the completions endpoint (which takes a string 'text'); quick scripts passing a raw string; LLM(... ) vs chat API confusion.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/be746aec03263e34. Report an issue: GitHub.