Summary
OpenClaw can persist assistant messages with empty content: [] after stream/provider errors. With AWS Bedrock Converse, any later replay containing that assistant turn fails with:
Validation error: The content field in the Message object at messages.N is empty. Add a ContentBlock object to the content field and try again.
Once this happens, the session can enter a death loop: every new inbound message replays the same invalid assistant turn, Bedrock rejects the request, and another failed/error assistant turn may be persisted.
Environment
- OpenClaw:
2026.4.23
- Provider/API: AWS Bedrock Converse / Converse stream
- Observed with embedded agent sessions and Feishu channel delivery
Observed symptoms
- A session stops responding after one invalid assistant turn is written.
- Gateway restart does not help because the invalid JSONL entry is persisted.
- New user messages keep failing at Bedrock validation before the model can answer.
- In some sessions, transcript-only assistant entries such as OpenClaw delivery mirror/injected messages can also be replayed to the provider.
Root cause pattern
There are three related transcript hygiene gaps:
- Stream/provider error assistant messages can be built with
content: [].
- Replay normalization currently handles string assistant content, but does not defensively normalize/drop empty or invalid assistant content arrays before provider replay.
- Session file repair repairs malformed JSONL lines, but does not repair semantically invalid assistant messages that are valid JSON yet invalid for provider replay.
For Bedrock, an assistant message must contain at least one content block. Empty assistant arrays are therefore a hard replay poison.
Suggested fix
A robust fix would likely include:
- Ensure stream error assistant messages always contain a non-empty text block, e.g. a short sentinel such as
[assistant turn failed before producing content].
- In replay history normalization, normalize assistant content arrays by dropping invalid/empty text blocks and replacing an empty result with the same sentinel text block.
- Filter transcript-only OpenClaw assistant messages from provider replay when
provider === "openclaw" and model is delivery-mirror or gateway-injected.
- Extend session file repair to rewrite semantically invalid assistant messages and optionally drop transcript-only assistant messages, not just malformed JSONL lines.
- Make the repair idempotent so a healthy session is not rewritten repeatedly.
Regression tests that would cover this
buildStreamErrorAssistantMessage never returns content: [].
normalizeAssistantReplayContent converts assistant content: [] to a non-empty text content block.
normalizeAssistantReplayContent filters OpenClaw delivery-mirror / gateway-injected assistant messages before provider replay.
repairSessionFileIfNeeded repairs persisted assistant content: [] and is idempotent on a second run.
Local validation
A local hotfix with the behavior above was applied to a 2026.4.23 installation and tested against previously poisoned sessions. After repair:
- Main session: tool calls/results remained paired.
- Subagent long task: completed with web fetch, file reads, HTML generation, screenshot, and Feishu image delivery.
- No
synthetic error result for transcript repair tool results appeared.
- No empty assistant content remained.
- No new
content field ... is empty Bedrock validation error occurred.
I am filing this as an issue rather than a PR because the local validation was done against packaged dist output; the upstream fix should be implemented in the TypeScript sources and covered by the tests above.
Summary
OpenClaw can persist assistant messages with empty
content: []after stream/provider errors. With AWS Bedrock Converse, any later replay containing that assistant turn fails with:Once this happens, the session can enter a death loop: every new inbound message replays the same invalid assistant turn, Bedrock rejects the request, and another failed/error assistant turn may be persisted.
Environment
2026.4.23Observed symptoms
Root cause pattern
There are three related transcript hygiene gaps:
content: [].For Bedrock, an assistant message must contain at least one content block. Empty assistant arrays are therefore a hard replay poison.
Suggested fix
A robust fix would likely include:
[assistant turn failed before producing content].provider === "openclaw"andmodelisdelivery-mirrororgateway-injected.Regression tests that would cover this
buildStreamErrorAssistantMessagenever returnscontent: [].normalizeAssistantReplayContentconverts assistantcontent: []to a non-empty text content block.normalizeAssistantReplayContentfilters OpenClawdelivery-mirror/gateway-injectedassistant messages before provider replay.repairSessionFileIfNeededrepairs persisted assistantcontent: []and is idempotent on a second run.Local validation
A local hotfix with the behavior above was applied to a 2026.4.23 installation and tested against previously poisoned sessions. After repair:
synthetic error result for transcript repairtool results appeared.content field ... is emptyBedrock validation error occurred.I am filing this as an issue rather than a PR because the local validation was done against packaged
distoutput; the upstream fix should be implemented in the TypeScript sources and covered by the tests above.