BerriAI/litellm · error · OCIError
Each content item must have a string `type` field
Error message
Each content item must have a string `type` field
What it means
In the OCI GENERIC message adapter, every content-part dict must carry a string 'type' field identifying it as text or image_url. If 'type' is missing, None, or not a string, OCIError(400) 'Each content item must have a string `type` field' is raised during request construction. The validation happens locally, so no tokens are spent.
Source
Thrown at litellm/llms/oci/chat/generic.py:76
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,
message="Content item of type `text` must have a string `text` field",
)
new_content.append(OCITextContentPart(text=text))
View on GitHub (pinned to 6c2dcb801b)
Solutions
- Add an explicit string 'type' to every part: 'text' or 'image_url'.
- Validate messages with a small pre-flight check (see defense) that asserts each part has isinstance(part.get('type'), str).
- Generate parts through one helper function so the discriminator is always set.
Example fix
# before
content=[{'text':'hello'}, {'type':'image_url','image_url':{'url':u}}]
# after
content=[{'type':'text','text':'hello'}, {'type':'image_url','image_url':{'url':u}}] Defensive patterns
Strategy: type-guard
Validate before calling
for i, part in enumerate(content):
assert isinstance(part.get('type'), str), f'content[{i}] missing string type: {part!r}' Type guard
def has_string_type(part: object) -> bool:
"""True when part is a dict carrying a string 'type' discriminator."""
return isinstance(part, dict) and isinstance(part.get('type'), str) Try / catch
try:
litellm.completion(model='oci/...', messages=msgs)
except OCIError as e:
if 'string `type` field' in str(e):
msgs = add_missing_types(msgs)
raise Prevention
- Never hand-write content parts without a typed constructor like text_part(s) / image_part(url).
- Lint message payloads in tests with a schema check before they reach litellm.
When it happens
Trigger: Passing a content part like {'text':'hi'} (type omitted), {'type':None,...}, or a part where 'type' was set from an untyped variable that ended up non-string, in a message sent to an oci/ GENERIC model.
Common situations: Hand-building content parts and forgetting the discriminator; migrating code from an API that infers the part type from keys; data-driven prompts where a template leaves 'type' empty for some rows.
Related errors
- Each content item must be a dictionary
- Content item of type `text` must have a string `text` field
- Prop `image_url` must be a string or an object with a `url`
- Each tool call must be a dictionary
- Content type `{item_type}` is not supported by OCI
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/27e4abc2c6d9a100.
Report an issue: GitHub.