BerriAI/litellm · error · ValueError
Message must have a 'role' field
Error message
Message {i} must have a 'role' field What it means
Raised when message i in a Converse-format count-tokens request is a dict but lacks the required 'role' key. Converse messages must carry both 'role' (e.g. 'user'/'assistant') and 'content'; validation reports the exact index so the malformed message is easy to locate.
Solutions
- Add the role to message i: {'role': 'user', 'content': 'hello'}
- If porting from OpenAI-style bodies, rename sender/author fields to 'role'
- Validate with a small helper before sending (see defense snippet) so all messages are checked at once
Example fix
# before
messages = [{'content': 'hello'}]
# after
messages = [{'role': 'user', 'content': 'hello'}] Defensive patterns
Strategy: type-guard
Validate before calling
def assert_roles_present(messages: list[dict]) -> None:
for i, m in enumerate(messages):
if 'role' not in m:
raise ValueError(f'message {i} missing role')
if m['role'] not in ('user', 'assistant'):
raise ValueError(f"message {i} role {m['role']!r} not user/assistant") Type guard
def messages_have_roles(messages: list) -> bool:
return all(isinstance(m, dict) and 'role' in m for m in messages) Try / catch
try:
handler.count_tokens(body)
except ValueError as e:
m = re.search(r"Message (\d+) must have a 'role' field", str(e))
if m:
i = int(m.group(1))
body['messages'][i]['role'] = 'user' # or derive from context
handler.count_tokens(body)
else:
raise Prevention
- Rename sender/author to role in your adapter layer
- Use a Message TypedDict so missing keys fail static checks
- Validate the whole list once before sending instead of fixing index-by-index
When it happens
Trigger: messages=[{'content': 'hello'}] (content-only dicts); using 'sender' or 'author' instead of 'role'; message dicts built by dict-merge where the role key was dropped.
Common situations: Translating from another provider's message format that names the field differently; generic {'text': ...} payloads from internal tooling; partial dict copies ({**m for m in ...} losing keys via filters).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Message must have a 'content' field
- Message must be a dictionary
- messages parameter is required for Converse input
- messages must be a list
- model parameter is required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/a11fe007a7036703.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/bedrock/count_tokens/transformation.py:274
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 77b7c6c40c)