BerriAI/litellm · error · ValueError
Message {i} must be a dictionary
Error message
Message {i} must be a dictionary What it means
Per-message structural validation for Converse-style count-tokens input: every element of 'messages' must be a dict. A string, tuple, or None element at index i raises ValueError naming the offending index.
Source
Thrown at litellm/llms/bedrock/count_tokens/transformation.py:271
ValueError: If the request is invalid
"""
if not request_data.get("model"):
raise ValueError("model parameter is required")
input_type: Final = self._detect_input_type(request_data)
if input_type == "converse":
# Validate Converse format (messages-based)
messages: Final = request_data.get("messages", [])
if not messages:
raise ValueError("messages parameter is required for Converse input")
if not isinstance(messages, list):
raise ValueError("messages must be a list")
for i, message in enumerate(messages):
if not isinstance(message, dict):
raise ValueError(f"Message {i} must be a dictionary")
if "role" not in message:
raise ValueError(f"Message {i} must have a 'role' field")
if "content" not in message:
raise ValueError(f"Message {i} must have a 'content' field")
else:
# For InvokeModel format, we need at least some content to count tokens
# The content structure varies by model, so we do minimal validation
if len(request_data) <= 1: # Only has 'model' field
raise ValueError("Request must contain content to count tokens")
View on GitHub (pinned to 6c2dcb801b)
Solutions
- Convert every turn to {'role': ..., 'content': ...} dicts
- Sanitize: messages = [m if isinstance(m, dict) else {'role': 'user', 'content': [{'text': str(m)}]} for m in messages]
Example fix
# before
req = {'model': m, 'messages': ['hello', 'hi']}
# after
req = {'model': m, 'messages': [
{'role': 'user', 'content': [{'text': 'hello'}]},
{'role': 'assistant', 'content': [{'text': 'hi'}]},
]} Defensive patterns
Strategy: type-guard
Validate before calling
for i, m in enumerate(req.get("messages", [])):
if not isinstance(m, dict):
raise TypeError(f"Message {i} must be a dictionary") Type guard
def is_valid_message(m) -> bool:
return isinstance(m, dict) and isinstance(m.get("role"), str) and ("content" in m) Prevention
- Normalize plain-string turns into message dicts at ingestion
- Validate the whole conversation with one helper before any LiteLLM call
When it happens
Trigger: messages = ['hello world', ...] where plain strings were passed instead of message objects, or mixed lists where one element is a content block rather than a message.
Common situations: Porting code from chat APIs that accept plain-string turns, or array spreads that accidentally inline content blocks.
Related errors
- messages must be a list
- model parameter is required
- messages parameter is required for Converse input
- Message {i} must have a 'role' field
- Message {i} must have a 'content' field
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/34736f53a762b65d.
Report an issue: GitHub.