BerriAI/litellm · error · ValueError
Message must have a 'content' field
Error message
Message {i} must have a 'content' field What it means
Raised when message i in a Converse-format count-tokens request is a dict with a 'role' but no 'content' key. Content is what actually gets tokenized, so a message without it cannot contribute to a count; the error names the index of the offending message.
Solutions
- Add content to message i, even if empty: {'role': 'user', 'content': ''} (empty content passes this validator)
- Rename alternate keys to 'content' when porting from other formats
- When deleting content for redaction, keep the key with an empty value rather than removing it
Example fix
# before
messages = [{'role': 'user'}]
# after
messages = [{'role': 'user', 'content': 'Hello, world'}] Defensive patterns
Strategy: type-guard
Validate before calling
def assert_content_present(messages: list[dict]) -> None:
for i, m in enumerate(messages):
if 'content' not in m:
raise ValueError(f'message {i} missing content (use "" if empty by design)') Type guard
def messages_have_content(messages: list) -> bool:
return all(isinstance(m, dict) and 'content' 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 'content' field", str(e))
if m:
i = int(m.group(1))
body['messages'][i].setdefault('content', '')
handler.count_tokens(body)
else:
raise Prevention
- Map 'text'/'parts' fields to 'content' in your provider adapter
- Keep empty content as '' instead of deleting the key
- Build messages via a constructor that always sets both role and content
When it happens
Trigger: messages=[{'role': 'user'}] (role-only); content stored under different keys ('text', 'parts', 'blocks'); messages constructed from templates where the content placeholder was never filled and the key was omitted entirely.
Common situations: Migrating from APIs whose content field is named 'text'; emptying a message for moderation/redaction and deleting the key instead of setting it to '' or []; optional-content code paths that use dict.pop('content').
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 'role' 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/cc379b011ade9351.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/bedrock/count_tokens/transformation.py:277
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)