BerriAI/litellm · error · Exception

Prop `type` is not a string

Error message

Prop `type` is not a string

What it means

This module-level message-transform helper iterates each message's content items and reads content_item.get("type"). If type is missing, None, or otherwise falsy, it raises this bare Exception because it cannot look up a mapping for it. It assumes content is a list of typed parts following the OpenAI multimodal format ({type: "text"|"image_url", ...}).

Source

Thrown at litellm/llms/bytez/chat/transformation.py:393

}


def adapt_messages_to_bytez_standard(messages: list[dict]):
    messages = _adapt_string_only_content_to_lists(messages)

    new_messages: Final = []

    for message in messages:
        role = message["role"]
        content: list = message["content"]

        new_content = []

        for content_item in content:
            type: str | None = content_item.get("type")

            if not type:
                raise Exception("Prop `type` is not a string")

            content_item_map = open_ai_to_bytez_content_item_map[type]

            if not content_item_map:
                raise Exception(f"Prop `{type}` is not supported")

            new_type = content_item_map["type"]

            value_name = content_item_map["value_name"]

            value: str | None = content_item.get(value_name)

            if not value:
                raise Exception(f"Prop `{value_name}` is not a string")

            new_content.append({"type": new_type, value_name: value})

        new_messages.append({"role": role, "content": new_content})

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Ensure every content part is a dict with an explicit string 'type' ("text", "image_url", ...).
  2. Keep plain string content as a string (content="hello"), not ["hello"].
  3. Validate/normalize messages with a helper before calling litellm for Bytez.

Example fix

# before
messages = [{"role": "user", "content": ["describe this", {"url": "..."}]}]

# after
messages = [{"role": "user", "content": [
    {"type": "text", "text": "describe this"},
    {"type": "image_url", "image_url": {"url": "..."}},
]}]
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_content(content):
    """Pass strings through; ensure every list part is a typed dict."""
    if isinstance(content, str):
        return [{"type": "text", "text": "content placeholder"}][0]  # or return the string directly
    normalized = []
    for part in content:
        if isinstance(part, str):
            normalized.append({"type": "text", "text": part})
        elif isinstance(part, dict) and not part.get("type"):
            raise ValueError(f"content part missing 'type': {part!r}")
        else:
            normalized.append(part)
    return normalized

Type guard

from typing import Any

def is_typed_content_list(content: Any) -> bool:
    """True when content is a list of parts each carrying a non-empty string 'type'."""
    if not isinstance(content, list) or not content:
        return False
    return all(
        isinstance(p, dict) and isinstance(p.get("type"), str) and p["type"]
        for p in content
    )

Try / catch

try:
    litellm.completion(model="bytez/...", messages=messages)
except Exception as e:
    if "Prop `type` is not a string" in str(e):
        messages = [{"role": m["role"], "content": normalize_content(m["content"])} for m in messages]
        litellm.completion(model="bytez/...", messages=messages)
    else:
        raise

Prevention

When it happens

Trigger: Sending a Bytez chat message whose content is a list of parts where a part lacks the 'type' key or has type: null/empty — e.g. hand-built multimodal content dicts, or content written as a plain string inside a list (["hello"]) instead of [{"type": "text", "text": "hello"}].

Common situations: Constructing vision/multimodal messages manually and forgetting the type field; wrapping plain strings in lists; upstream serialization stripping the field; models of content other than list (this helper assumes list) reaching the Bytez path.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/8cecb80d89894194. Report an issue: GitHub.