Skip to content

[Bug] Azure Foundry Anthropic: SSE stream events concatenated without \n\n delimiter — raw JSON parse error surfaced to all user channels #32179

@yvesgagnongesys

Description

@yvesgagnongesys

Description

When using the azure-foundry-anthropic provider (Azure AI Foundry Anthropic endpoint at *.services.ai.azure.com/anthropic) with api: "anthropic-messages", the SSE stream occasionally delivers chunks where two SSE events are concatenated without a proper \n\n delimiter between them. The @anthropic-ai/sdk LineDecoder fails to split these correctly, causing JSON.parse() to receive a malformed string combining two events.

The error is then surfaced verbatim as a "run error" message to the user in Discord channels and webchat — on every session type (direct, group, sub-agents, cron).

Steps to Reproduce

  1. Configure an azure-foundry-anthropic provider pointing to https://<hub>.services.ai.azure.com/anthropic
  2. Use api: "anthropic-messages" with a Claude Sonnet 4.x model
  3. Run multiple concurrent agent sessions (crons + sub-agents + direct chat)
  4. Within 2 hours: observe SSE parse errors in gateway logs

Observed Behavior

Gateway logs (journalctl --user -u openclaw-gateway):

Could not parse message into JSON: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Director, Regulatory Affairs | 1"}}    event: content_block_delta
Could not parse message into JSON: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"ary_foevent: content_block_delta
Could not parse message into JSON: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}    }
Could not parse message into JSON: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":3,event: content_block_delta

Patterns observed:

  • Two events concatenated with spaces instead of \n\n: }} event: content_block_delta
  • Mid-JSON truncation with next event header: "partial_json":"ary_foevent: content_block_delta
  • Trailing whitespace garbage before closing brace: "text":","} }

Frequency: ~17 errors per 2 hours under moderate concurrency (10 concurrent agents, 8 sub-agents max).

Impact: [agent/embedded] embedded run agent end: isError=true — the error is delivered as a "run error" message to Discord channels and webchat on every occurrence. Users see raw JSON parse errors in all channels.

Expected Behavior

  1. The SSE parser should tolerate Azure Foundry's non-standard chunk delimiters (defensive splitting on event: keyword boundaries in addition to \n\n)
  2. OR: auto-retry the request (1-2 times) on transient SSE parse failures before surfacing to user
  3. At minimum: the error should NOT be delivered to end-user channels — it should be logged and silently retried

Environment

  • OpenClaw: 2026.3.1
  • @anthropic-ai/sdk: 0.73.0
  • Model: azure-foundry-anthropic/claude-sonnet-4-6 (custom provider, api: "anthropic-messages")
  • Provider endpoint: https://<hub>.services.ai.azure.com/anthropic
  • Node.js: v22.22.0
  • OS: Linux 6.17.0 (Azure VM, x64)

Root Cause Analysis

The @anthropic-ai/sdk/internal/decoders/line.ts LineDecoder correctly splits on \n and \r\n. However, Azure Foundry Anthropic's endpoint appears to occasionally send HTTP response chunks where the SSE event boundary (\n\n) is missing or replaced with whitespace. Two consecutive data: lines arrive merged in a single chunk without a newline separator, causing the LineDecoder to return one oversized "line" that contains both events — which then fails JSON.parse().

This is distinct from issue #14321 (C0 control characters). The issue here is event boundary encoding specific to Azure Foundry's streaming implementation.

Suggested Fix

In the SSE stream handler (@anthropic-ai/sdk/core/streaming.js → called from OpenClaw's streamSimpleAnthropic):

// Defensive split: if sse.data contains concatenated events, split on "event:" boundaries
function safeSplitSSEData(data: string): string {
  // If data contains "event:" mid-string (Azure Foundry concatenation artifact), 
  // truncate to first valid JSON object
  const eventIdx = data.search(/\s+event:/);
  if (eventIdx > 0) {
    return data.substring(0, eventIdx).trim();
  }
  return data;
}

Or alternatively: wrap the JSON.parse(sse.data) in a try/catch that silently retries the streaming request rather than surfacing the error to users.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions