sgl-project/sglang · error · ValueError

Invalid content format: {content_format}

Error message

Invalid content format: {content_format}

What it means

process_content_for_template_format dispatches on the shape of a message's content field (string, list-of-parts, etc.). This ValueError fires when content is a format the function has no branch for — typically a non-string, non-list type such as an int or dict.

Source

Thrown at python/sglang/srt/parser/jinja_template_utils.py:240

        return new_msg

    elif content_format == "string":
        # String format: flatten to text only (for templates like DeepSeek)
        text_parts = []
        for chunk in msg_dict["content"]:
            if isinstance(chunk, dict) and chunk.get("type") in ("text", "input_text"):
                text_parts.append(chunk["text"])
            # Note: For string format, we ignore images/audio since the template
            # doesn't expect structured content - multimodal placeholders would
            # need to be inserted differently

        new_msg = msg_dict.copy()
        new_msg["content"] = " ".join(text_parts) if text_parts else ""
        new_msg = {k: v for k, v in new_msg.items() if v is not None}
        return new_msg

    else:
        raise ValueError(f"Invalid content format: {content_format}")

View on GitHub (pinned to 0132848349)

Solutions

  1. Normalize content to a string or a list-of-parts list before applying the template
  2. Validate incoming request bodies against the OpenAI chat schema (content must be string or array)
  3. Convert non-string scalars with str(content) if your app allows them

Example fix

// before
messages = [{"role": "user", "content": 42}]
// after
messages = [{"role": "user", "content": "42"}]
Defensive patterns

Strategy: validation

Validate before calling

def content_ok(content):
    return isinstance(content, (str, list)) and (not isinstance(content, list) or all(isinstance(p, dict) for p in content))

for m in messages:
    if not content_ok(m.get("content")):
        m["content"] = str(m.get("content"))

Type guard

def is_valid_content(v: Any) -> TypeGuard[Union[str, list]]:
    return isinstance(v, str) or (isinstance(v, list) and all(isinstance(p, dict) for p in v))

Try / catch

try:
    rendered = _apply_jinja_template(messages, ...)
except ValueError as e:
    if "Invalid content format" in str(e):
        messages = normalize_contents(messages); rendered = _apply_jinja_template(messages, ...)
    else:
        raise

Prevention

When it happens

Trigger: Passing a message dict where content is an integer, dict, or None in a path not covered, e.g. {'role': 'user', 'content': 42} into _apply_jinja_template.

Common situations: Clients sending numeric/boolean content (some APIs allow it), None content on tool-role messages, or malformed hand-crafted request bodies.

Related errors


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