# Symptom

```
ValueError: Message dict must contain 'role' and 'content' keys, got {'role': 'HumanMessage', 'random_field': 'random value'}
```

## Confirm

Log the message list immediately before the model call. Find the dict the error quotes. Check its keys against the accepted shapes: message objects, `{"role": ..., "content": ...}` dicts, tuples, plain strings.

## Cause

- The dict uses the class name as the role (`"HumanMessage"` instead of `"user"`).
- A message was JSON-serialized and re-wrapped, so it is now a string containing a dict, or a dict with renamed keys.
- Custom code adds extra fields or renames `content`.

## Fix

Normalize to the OpenAI-style shape:

```python
{"role": "user", "content": "Hello world!"}
```

or construct real message objects (`HumanMessage(content=...)`). Fix the transformation where it happens (serializer, cache layer), not just at the call site.

## Verify

Re-run the invoke. If the list is built in a loop, assert the shape of every element before the call during development; the error only quotes the first offender.