Skip to content

Group chat context injection creates consecutive user-role messages, breaking Anthropic API compatibility #83419

Description

@NOVA-Openclaw

Description

OpenClaw's group chat message pipeline injects channel metadata (untrusted context block with sender info, channel topic, chat history) as a separate {role: "user"} message object in the API request array, followed by the actual user message as another {role: "user"} object. This creates consecutive same-role messages on every turn, including the very first turn of a fresh session.

The Anthropic API strictly requires role alternation (user → assistant → user → ...) and rejects requests with consecutive same-role messages. OpenRouter proxies return HTTP 500 for these rejections instead of the upstream 400, which triggers the OpenClaw failover cascade (see #83404).

Impact

  • Every fresh session starts broken on Anthropic models. The first turn always has roles: {system: 1, user: 2} — the metadata context and the actual message as separate user entries.
  • Silent fallback to Gemini models. Google's API is lenient about consecutive same-role messages and accepts them, so agents silently fall through to Gemini fallbacks on every initial turn. This has been happening across all agents in our deployment without being noticed until the fallback cascade bug (queue.mode followup causes duplicate user messages in session transcript during failover retry #83404) made it catastrophic.
  • Agents do not run on their configured primary model. Claude Opus 4.6 is configured as primary, but agents consistently start on Gemini Flash or other Google fallbacks because the first Anthropic attempt always fails.

Reproduction

  1. Configure a Discord group chat channel with an Anthropic primary model (e.g., anthropic/claude-opus-4.6 via OpenRouter)
  2. Send a message to the agent in the group channel
  3. Observe the API request payload — first turn will have:
messages: [
  {role: "system", content: "..."  },          // 60KB+ bootstrap context
  {role: "user",   content: "[metadata block]" },  // Injected conversation info
  {role: "user",   content: "[actual message]" }   // The real user message
]
  1. Anthropic rejects with 400 (consecutive user messages), OpenRouter returns 500, OpenClaw falls through to Gemini

Intercepted request from a clean session (first turn ever):

{
  "model": "anthropic/claude-opus-4.6",
  "messages": 3,
  "roles": {"system": 1, "user": 2},
  "consecutiveSameRole": 1,
  "bodyBytes": 118715,
  "tools": 28,
  "systemMsgChars": 61151
}

The two user messages contain:

  • msg[1]: Conversation info (untrusted metadata): {"chat_id": "channel:...", "sender_id": "...", ...}
  • msg[2]: @Graybeard say hello (the actual user message + channel metadata footer)

Expected Behavior

The metadata context and actual message content should be merged into a single {role: "user"} message before the request array is built. This ensures proper role alternation regardless of how many context blocks are injected.

Alternatively, OpenClaw's provider adapter for Anthropic/OpenAI-compatible APIs should squash consecutive same-role messages before sending the request.

Environment

  • OpenClaw version: 2026.5.12
  • Provider: OpenRouter (openai-completions API)
  • Affected models: All Anthropic models (claude-opus-4.6, claude-opus-4.5, claude-sonnet-4.6)
  • Unaffected models: Google Gemini models (lenient about consecutive roles)
  • Channel: Discord group chat with groupChat.visibleReplies: "automatic"
  • Config: messages.groupChat.historyLimit at default

Related

Metadata

Metadata

Assignees

Labels

P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions