This is a submission for the Hermes Agent Challenge.
I spent 20 minutes debugging a 400 error from the Anthropic API. The error message was messages: roles must alternate between "user" and "assistant". I had accidentally appended two user messages in a row. By the time the request reached the API, the bug was three layers deep in my agent loop.
The fix: validate the message list before sending it. That's agent-message-validator.
Check before sending
from agent_message_validator import validate_messages
result = validate_messages(messages)
if not result.ok:
print(result.summary())
# 1 error(s) in 4 message(s):
# - consecutive same-role messages at index 2 and 3 (role='user')
response = client.messages.create(...)
Raise on error
from agent_message_validator import check_messages
check_messages(messages) # raises MessageValidationError if invalid
response = client.messages.create(...)
Quick boolean check
from agent_message_validator import is_valid
if is_valid(messages):
response = client.messages.create(...)
else:
# fix messages before sending
What it catches
Consecutive same-role messages — the most common error in multi-turn agents:
msgs = [
{"role": "user", "content": "First question"},
{"role": "user", "content": "Follow-up"}, # 400 waiting to happen
]
validate_messages(msgs).ok # False
First message from assistant:
msgs = [{"role": "assistant", "content": "Hello"}]
validate_messages(msgs).ok # False
Unmatched tool_use without tool_result:
msgs = [
{"role": "user", "content": "Search"},
{"role": "assistant", "content": [
{"type": "tool_use", "id": "tu_001", "name": "search", "input": {}}
]},
# Never sent the tool result
{"role": "user", "content": "Never mind"},
]
result = validate_messages(msgs)
# "tool_use 'tu_001' has no matching tool_result"
Orphan tool_result (no prior tool_use):
msgs = [
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "tu_999", "content": "..."}
]},
]
result = validate_messages(msgs)
# "tool_result for 'tu_999' has no matching tool_use"
Empty content and missing role/content keys.
ValidationResult
result = validate_messages(messages)
result.ok # True / False
result.errors # ["consecutive same-role messages at ...", ...]
result.error_count # int
result.message_count
bool(result) # same as result.ok
result.summary() # human-readable string
Multiple errors reported at once
The validator runs all checks and returns all errors, not just the first:
# messages where the first message is assistant AND two consecutive roles
result = validate_messages(bad_messages)
result.error_count # 2
Zero dependencies
Standard library only: dataclasses. Nothing else.
git clone https://github.com/MukundaKatta/agent-message-validator
cd agent-message-validator && pip install -e .
Repo: https://github.com/MukundaKatta/agent-message-validator
Top comments (0)