{"record":{"id":"df7f5e9cecf7855d","repo":"BerriAI/litellm","slug":"content-can-only-contain-strings-or-openai-conte","errorCode":null,"errorMessage":"`content` can only contain strings or openai content dicts","messagePattern":"`content` can only contain strings or openai content dicts","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/llms/bytez/chat/transformation.py","lineNumber":442,"sourceCode":"        content = message.get(\"content\")\n\n        new_content = []\n\n        if isinstance(content, str):\n            new_content.append({\"type\": \"text\", \"text\": content})\n\n        elif isinstance(content, dict):\n            new_content.append(content)\n\n        elif isinstance(content, list):\n            new_content_items = []\n            for content_item in content:\n                if isinstance(content_item, str):\n                    new_content_items.append({\"type\": \"text\", \"text\": content_item})\n                elif isinstance(content_item, dict):\n                    new_content_items.append(content_item)\n                else:\n                    raise Exception(\"`content` can only contain strings or openai content dicts\")\n\n            new_content += new_content_items\n        else:\n            raise Exception(\"Content must be a string\")\n\n        new_messages.append({\"role\": role, \"content\": new_content})\n\n    return new_messages\n\n\n# TODO get this from the api instead of doing it here, will require backend work\ndef get_tokens_from_messages(messages: list[dict]):\n    total = 0\n\n    for message in messages:\n        content: list[dict] = message[\"content\"]\n\n        for content_item in content:","sourceCodeStart":424,"sourceCodeEnd":460,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/bytez/chat/transformation.py#L424-L460","documentation":"Thrown by Bytez's `_adapt_string_only_content_to_lists` helper when a message's `content` list contains an element that is neither a `str` nor a `dict`. The helper normalizes mixed string/dict content into a uniform list of dicts; any other Python object (int, None, bytes, Pydantic model) is rejected before the request is sent.","triggerScenarios":"Passing `content: [None]`, `content: [123]`, or a list containing an unserialized object (e.g. a Pydantic message part or PIL Image) to a Bytez completion call. String content and dict content items are fine; everything else raises.","commonSituations":"Building messages programmatically and accidentally appending a non-serialized object or None; passing OpenAI SDK typed objects (e.g. `ChatCompletionContentPartImage`) directly instead of `.model_dump()` dicts.","solutions":["Serialize every content item to a plain str or dict before calling litellm (e.g. call `.model_dump()` on Pydantic parts).","Check for None elements introduced by conditional appends (`parts.append(x if cond else None)`).","Add a guard like `assert all(isinstance(p, (str, dict)) for p in content)` in dev builds.","Inspect the exact message list with a debug print right before the completion call."],"exampleFix":"// before\ncontent = [\"describe\", None, image_part_pydantic]\n\n// after\ncontent = [\"describe\", image_part_pydantic.model_dump()]","handlingStrategy":"type-guard","validationCode":"def normalize_content_items(items):\n    out = []\n    for it in items:\n        if isinstance(it, str):\n            out.append({\"type\": \"text\", \"text\": it})\n        elif isinstance(it, dict):\n            out.append(it)\n        elif hasattr(it, \"model_dump\"):\n            out.append(it.model_dump())\n        else:\n            raise TypeError(f\"unsupported content item: {type(it)!r}\")\n    return out","typeGuard":"def is_valid_content_item(item) -> bool:\n    return isinstance(item, (str, dict))","tryCatchPattern":null,"preventionTips":["Call .model_dump() on Pydantic message parts before passing them in.","Avoid conditional appends that can insert None.","Keep message construction in one typed builder function."],"tags":["bytez","content-parts","request-validation","serialization"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}