BerriAI/litellm · error · OCIError
Each content item must be a dictionary
Error message
Each content item must be a dictionary
What it means
When translating an OpenAI-format chat message to OCI GENERIC format, LiteLLM iterates multipart `content` arrays and requires every element to be a dict (an OpenAI content-part object). Encountering a non-dict item (e.g. a bare string) raises OCIError 400 before any network call. This is strict input validation: OCI GENERIC accepts typed content parts, so raw strings inside a list are rejected early.
Solutions
- Wrap bare strings in a text part: [{"type":"text","text":"just a string"}]
- Or hoist the whole message to plain string content: {"role":"user","content":"just a string"}
- Validate/normalize your message builder so content lists only ever contain dicts with a type key
- If a framework feeds you mixed lists, map str -> {"type":"text","text":s} before calling litellm
Example fix
# before
messages = [{"role": "user", "content": ["analyze this"]}]
litellm.completion(model="oci/generic.my-model", messages=messages) # 400
# after
messages = [{"role": "user", "content": [{"type": "text", "text": "analyze this"}]}] Defensive patterns
Strategy: validation
Validate before calling
def normalize_content(content):
if isinstance(content, str):
return content
return [
{"type": "text", "text": item} if isinstance(item, str) else item
for item in content
]
messages = [{"role": "user", "content": normalize_content(msg["content"])} for msg in messages] Type guard
def is_valid_oci_content(content) -> bool:
if isinstance(content, str):
return True
return isinstance(content, list) and all(isinstance(p, dict) for p in content) Prevention
- Construct content lists only through one helper that always emits part dicts
- Never splice raw user input directly into multipart content arrays
When it happens
Trigger: Calling litellm.completion(model="oci/generic...", messages=[{"role":"user","content":["just a string"]}]) — a content list whose element is not a dict. Also triggered by frameworks that build content lists with mixed str/dict elements before forwarding to LiteLLM.
Common situations: Hand-built content arrays mixing strings and part objects; LangChain/custom wrappers that append plain text into a multimodal content list; migrating OpenAI calls (which tolerate lenient shapes) to OCI GENERIC models; data from user input spliced unvalidated into content.
Related errors
- Content item of type `text` must have a string `text` field
- Content type ` ` is not supported by OCI
- Each content item must have a string `type` field
- Message `content` must be a string or list of content parts
- `content` can only contain strings or openai content dicts
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/f52120bf76b1db22.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/oci/chat/generic.py:72
# ---------------------------------------------------------------------------
# Message building
# ---------------------------------------------------------------------------
def adapt_messages_to_generic_oci_standard_content_message(role: str, content: str | list) -> OCIMessage:
"""Convert a plain-text or multipart content message to OCI format."""
new_content: Final[list[OCIContentPartUnion]] = []
if isinstance(content, str):
return OCIMessage(
role=open_ai_to_generic_oci_role_map[role],
content=[OCITextContentPart(text=content)],
toolCalls=None,
toolCallId=None,
)
for content_item in content:
if not isinstance(content_item, dict):
raise OCIError(status_code=400, message="Each content item must be a dictionary")
item_type = content_item.get("type")
if not isinstance(item_type, str):
raise OCIError(
status_code=400,
message="Each content item must have a string `type` field",
)
if item_type not in ["text", "image_url"]:
raise OCIError(
status_code=400,
message=f"Content type `{item_type}` is not supported by OCI",
)
if item_type == "text":
text = content_item.get("text")
if not isinstance(text, str):
raise OCIError(
status_code=400,View on GitHub (pinned to 77b7c6c40c)