openclaw - ✅(Solved) Fix MiniMax M2.7 intermittently returns 400/2013 ("chat content is empty") after tool call chains [2 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#74589Fetched 2026-04-30 06:22:34
View on GitHub
Comments
2
Participants
3
Timeline
4
Reactions
2
Author
Timeline (top)
commented ×2cross-referenced ×2

Error Message

b) Proxy/network truncation — there's a Clash Verge proxy between the gateway and MiniMax. A late-chunk truncation could drop the last assistant message while leaving the JSON syntactically valid. But I'd expect a parse error, not a well-formed empty messages: []. So low probability, not ruled out. c) MiniMax server-side — 2013 is a known MiniMax error for genuinely empty payloads. I've confirmed the API key and quota are OK via direct curl. The error is consistent with what MiniMax sends when it gets {"messages":[]} — so the request is well-formed but empty.

Root Cause

What would help

  • If someone on the core team knows the MiniMax adapter's message filtering logic, that's where I'd look first
  • A provider-layer guard that replaces an empty messages: [] with a fallback placeholder ([{role: "user", content: "."}]) before sending would make this self-healing regardless of root cause

Fix Action

Fix / Workaround

Workaround

  • Session transcript repair (removes the broken assistant message) recovers the session
  • Switching the model (even temporarily) breaks the deadlock

PR fix notes

PR #74731: fix(minimax): guard empty anthropic messages

Description (problem / solution / changelog)

Root cause

MiniMax M2.7 uses the Anthropic-compatible transport. That transport filtered blank or unsupported replay content during convertAnthropicMessages, then sent the converted array directly. If the original session history was already empty, or every replay item was filtered out, the provider request could contain messages: [] and MiniMax returned chat content is empty.

Linked issue

Fixes #74589.

Why the fix is safe

The change is limited to the final Anthropic-compatible payload boundary. Valid converted messages are preserved unchanged. Only the invalid zero-message case receives a minimal user fallback before the existing payload policy runs, so providers do not see an empty Anthropic Messages request.

Security and runtime controls unchanged

This does not change auth, model routing, tool permissions, proxy/TLS policy, transcript persistence, or hook behavior. The guard is runtime-enforced in the transport payload builder rather than relying on prompt instructions.

Tests run

  • pnpm exec oxfmt --check --threads=1 src/agents/anthropic-transport-stream.ts src/agents/anthropic-transport-stream.test.ts CHANGELOG.md
  • git diff --check
  • pnpm changed:lanes --json
  • pnpm test src/agents/anthropic-transport-stream.test.ts -t "minimal user fallback|replaces empty text-only tool results"
  • pnpm test src/agents/anthropic-transport-stream.test.ts
  • pnpm test src/agents/anthropic-transport-stream.test.ts -t "minimal user fallback"
  • pnpm check:changed

Out of scope

  • No embedded-run prompt guard changes; #73929 remains the separate blank replay-history guard for #73926.
  • No MiniMax-specific retry/fallback policy changes.
  • No transcript repair or session-store migration changes.

AI-assisted: implemented and self-reviewed in Cursor.

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/anthropic-transport-stream.test.ts (modified, +55/-0)
  • src/agents/anthropic-transport-stream.ts (modified, +11/-1)

PR #73929: fix(agents): skip blank replay history prompts

Description (problem / solution / changelog)

Summary

  • Tighten the embedded-run prompt content guard so blank replay-history entries do not count as model-visible input.
  • Add regression coverage for blank string/object/array replay content while preserving structured non-text history such as images.
  • Add an Unreleased changelog entry for #73926.

Root Cause

hasPromptSubmissionContent treated any replay-history entry as content by checking only messages.length. During /new or /reset races, stale empty user/assistant entries could therefore bypass the empty prompt/history/images skip path and reach provider dispatch with no model-visible input.

Linked Issue

Fixes #73926.

Why This Is Safe

The change keeps the existing dispatch boundary behavior: submissions with prompt text, prompt images, or model-visible replay history still run. It only changes the history side of the guard from array presence to visible content presence, matching the sanitizer behavior that already drops blank user replay content.

Security And Runtime Controls

No security or authorization controls change. This does not add a prompt-text policy, alter model routing, or relax tool/runtime permissions; it only prevents blank payloads from being submitted.

Tests Run

  • git diff --check
  • pnpm test src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts
  • pnpm test src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts test/scripts/check-changelog-attributions.test.ts
  • pnpm changed:lanes --json
  • pnpm check:changed

Out Of Scope

  • No reset/startup prompt injection changes.
  • No active-memory scheduling or rebuild-order changes.
  • No provider adapter changes beyond avoiding empty submissions at the existing guard.

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts (modified, +22/-0)
  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts (modified, +29/-1)

Code Example

HTTP 400 | code 2013 | chat content is empty
RAW_BUFFERClick to expand / collapse

Setup

  • OpenClaw 2026.4.26
  • Main model: MiniMax-M2.7 via minimax-portal (Anthropic-compatible endpoint)
  • Fallback: deepseek/deepseek-v4-flash
  • Plugin: memory-lancedb-pro (but see below — not the culprit)

What happens

After a sequence of 2+ tool calls during a single agent turn, MiniMax starts returning:

HTTP 400 | code 2013 | chat content is empty

OpenClaw then falls back to DeepSeek. But the session state gets polluted — subsequent turns show flaky behavior, sometimes need manual session transcript repair to recover.

What I've ruled out

I dug into memory-lancedb-pro's source to check if its hooks were somehow zeroing out the messages array:

HookDoes whatModifies messages?
agent_endReturns early if !messages || messages.length === 0 — safe skipNo
before_prompt_buildReads event.prompt for recall, doesn't touch anythingNo
message_receivedPushes user text into a pending queueNo
before_message_writeJust loggingNo

All hooks are read-only or skip-on-empty. The plugin is a downstream observer here, not the source.

Also: the agent_end hook got the empty messages array from the session store, not from MiniMax's response — so the empty data exists before any API call is attempted.

What I'm not sure about

I have hypotheses but no smoking gun:

a) Provider adapter boundary case — strongest guess. When OpenClaw formats the message list for MiniMax (via the Anthropic-compatible or generic OpenAI-compatible adapter), a specific combination of tool result + assistant response could produce an empty filtered array. For example if all messages get collapsed into system messages that the adapter doesn't forward.

b) Proxy/network truncation — there's a Clash Verge proxy between the gateway and MiniMax. A late-chunk truncation could drop the last assistant message while leaving the JSON syntactically valid. But I'd expect a parse error, not a well-formed empty messages: []. So low probability, not ruled out.

c) MiniMax server-side — 2013 is a known MiniMax error for genuinely empty payloads. I've confirmed the API key and quota are OK via direct curl. The error is consistent with what MiniMax sends when it gets {"messages":[]} — so the request is well-formed but empty.

Reproduce

Intermittent. Haven't found a minimal repro yet. Pattern: heavy tool-calling sessions (3+ back-to-back tool uses with long assistant responses).

Workaround

  • Session transcript repair (removes the broken assistant message) recovers the session
  • Switching the model (even temporarily) breaks the deadlock

What would help

  • If someone on the core team knows the MiniMax adapter's message filtering logic, that's where I'd look first
  • A provider-layer guard that replaces an empty messages: [] with a fallback placeholder ([{role: "user", content: "."}]) before sending would make this self-healing regardless of root cause

The issue isn't critical (fallback works, recovery is manual but reliable). But it burns a session when it hits, and the fallback model switch can lose context.

Labels: bug, minimax, provider

extent analysis

TL;DR

Implementing a provider-layer guard to replace empty messages: [] with a fallback placeholder may resolve the issue.

Guidance

  • Investigate the MiniMax adapter's message filtering logic to understand how it handles specific combinations of tool results and assistant responses.
  • Verify if the issue is related to the provider adapter boundary case by checking the formatted message list for MiniMax.
  • Consider adding a temporary workaround to replace empty messages: [] with a fallback placeholder, such as [{role: "user", content: "."}], to make the session self-healing.
  • Review the Clash Verge proxy configuration to ensure it is not causing any issues with the request or response.

Example

// Example of a provider-layer guard to replace empty messages with a fallback placeholder
if (messages.length === 0) {
  messages = [{ role: "user", content: "." }];
}

Notes

The root cause of the issue is still uncertain, and further investigation is needed to determine the exact cause. The proposed solution is a workaround that may resolve the issue, but it may not address the underlying problem.

Recommendation

Apply the workaround by implementing a provider-layer guard to replace empty messages: [] with a fallback placeholder, as it may resolve the issue and make the session self-healing.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix MiniMax M2.7 intermittently returns 400/2013 ("chat content is empty") after tool call chains [2 pull requests, 2 comments, 3 participants]