openclaw - 💡(How to fix) Fix Slack/Telegram delivery layer: posts raw errorMessage verbatim and concatenates multiple text content items from assistant messages [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

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#69737Fetched 2026-04-22 07:48:57
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

OpenClaw's chat delivery layer (Slack verified; Telegram suspected same code path) posts raw assistant message content without sanitization in two cases, leading to user-visible confusion:

  1. Raw API errorMessage surfacing. When an assistant message has stopReason=error and the provider populates errorMessage with raw upstream API error text (e.g., an OpenAI 500 with a request ID and a help.openai.com link), OpenClaw posts that errorMessage verbatim to the configured delivery channel.

  2. Multiple text content items concatenated. When an assistant message contains more than one text content item (observed after parallel tool calls with the gpt-5.4 / openai-codex-responses provider — the model emits one text item per parallel tool branch), OpenClaw concatenates all text items into a single chat post instead of selecting one.

Both are in the same code path: the delivery layer doesn't sanitize assistant message content before posting to the user-facing channel.

Error Message

  1. Raw API errorMessage surfacing. When an assistant message has stopReason=error and the provider populates errorMessage with raw upstream API error text (e.g., an OpenAI 500 with a request ID and a help.openai.com link), OpenClaw posts that errorMessage verbatim to the configured delivery channel. stopReason: error errorMessage: "The server had an error processing your request. Sorry about that! help.openai.com if you keep seeing this error. (Please include the For stopReason=error: if (msg.stopReason === 'error') return GENERIC_ERROR_FALLBACK; // or null to suppress

Root Cause

OpenClaw's chat delivery layer (Slack verified; Telegram suspected same code path) posts raw assistant message content without sanitization in two cases, leading to user-visible confusion:

  1. Raw API errorMessage surfacing. When an assistant message has stopReason=error and the provider populates errorMessage with raw upstream API error text (e.g., an OpenAI 500 with a request ID and a help.openai.com link), OpenClaw posts that errorMessage verbatim to the configured delivery channel.

  2. Multiple text content items concatenated. When an assistant message contains more than one text content item (observed after parallel tool calls with the gpt-5.4 / openai-codex-responses provider — the model emits one text item per parallel tool branch), OpenClaw concatenates all text items into a single chat post instead of selecting one.

Both are in the same code path: the delivery layer doesn't sanitize assistant message content before posting to the user-facing channel.

Code Example

stopReason: error
content: []
errorMessage: "The server had an error processing your request. Sorry about that!
               You can retry your request, or contact us through our help center at
               help.openai.com if you keep seeing this error. (Please include the
               request ID <uuid> in your email.)"

---

content:
  - type: text
    text: "<single paragraph answer to the user's question, variant 1>"  (~120 chars)
  - type: text
    text: "<same paragraph answer, slightly different wording>"           (~136 chars)
stopReason: stop

---

function buildPostText(msg: AssistantMessage): string | null {
  if (msg.stopReason === 'error') return GENERIC_ERROR_FALLBACK; // or null to suppress
  const texts = (msg.content ?? []).filter(c => c.type === 'text' && c.text?.trim());
  if (texts.length === 0) return null;
  if (texts.length === 1) return texts[0].text;
  return texts[texts.length - 1].text; // pick-last; behind a config flag would be even better
}
RAW_BUFFERClick to expand / collapse

Summary

OpenClaw's chat delivery layer (Slack verified; Telegram suspected same code path) posts raw assistant message content without sanitization in two cases, leading to user-visible confusion:

  1. Raw API errorMessage surfacing. When an assistant message has stopReason=error and the provider populates errorMessage with raw upstream API error text (e.g., an OpenAI 500 with a request ID and a help.openai.com link), OpenClaw posts that errorMessage verbatim to the configured delivery channel.

  2. Multiple text content items concatenated. When an assistant message contains more than one text content item (observed after parallel tool calls with the gpt-5.4 / openai-codex-responses provider — the model emits one text item per parallel tool branch), OpenClaw concatenates all text items into a single chat post instead of selecting one.

Both are in the same code path: the delivery layer doesn't sanitize assistant message content before posting to the user-facing channel.

Environment

  • OpenClaw: 2026.4.14
  • Provider: openai-codex (using api: openai-codex-responses)
  • Model: gpt-5.4
  • Delivery channel verified: Slack (same code path likely for Telegram; untested)

Evidence — Bug 1 (errorMessage surfacing)

A scheduled cron fire hit an OpenAI 500. The assistant message written to the session store had:

stopReason: error
content: []
errorMessage: "The server had an error processing your request. Sorry about that!
               You can retry your request, or contact us through our help center at
               help.openai.com if you keep seeing this error. (Please include the
               request ID <uuid> in your email.)"

The delivery layer posted the errorMessage text verbatim to the end user's Slack DM.

Evidence — Bug 2 (multiple text content items)

An interactive session, preceded by an assistant turn with two parallel tool calls, produced one assistant message containing two text content items:

content:
  - type: text
    text: "<single paragraph answer to the user's question, variant 1>"  (~120 chars)
  - type: text
    text: "<same paragraph answer, slightly different wording>"           (~136 chars)
stopReason: stop

Slack delivery concatenated both items into one post, visible to the user as a near-duplicate paragraph with slight wording variation between the two halves. The two content items appear to be emitted one per parallel tool branch — a model behavior we can't rely on not happening.

Expected behavior

For stopReason=error:

  • Suppress the message entirely (admin-log server-side only), OR
  • Substitute a generic user-facing fallback (e.g., "Temporary issue — will retry shortly."), OR
  • Retry with backoff before posting
  • Never post the raw errorMessage verbatim to end users

For multi-text-item messages:

  • Select one text item to post (most useful: the last non-empty), OR
  • Expose a config flag: pick-last | pick-longest | concat (current) | separate-messages
  • concat should not be the default

Proposed fix surface

Sanitization step in the delivery path, before posting. Rough sketch:

function buildPostText(msg: AssistantMessage): string | null {
  if (msg.stopReason === 'error') return GENERIC_ERROR_FALLBACK; // or null to suppress
  const texts = (msg.content ?? []).filter(c => c.type === 'text' && c.text?.trim());
  if (texts.length === 0) return null;
  if (texts.length === 1) return texts[0].text;
  return texts[texts.length - 1].text; // pick-last; behind a config flag would be even better
}

Why bundle them

Same code path. Same class of issue. Same sanitization function covers both. Addressing them together gives one review surface and one deploy.

Related / separate

Retry-with-backoff on transient provider errors is a separate/larger feature — not requested here; this issue focuses on the delivery-layer sanitization only.

Offer

Happy to test a PR against our production deployment and provide additional evidence (scrubbed of user data) if useful.

extent analysis

TL;DR

Implement a sanitization step in the delivery layer to handle stopReason=error and multiple text content items, preventing raw error messages and concatenated text from being posted to the user-facing channel.

Guidance

  • Introduce a buildPostText function to sanitize the assistant message content before posting, handling stopReason=error by returning a generic error fallback or suppressing the message.
  • Filter and process text content items to select one item to post, such as the last non-empty item, or provide a config flag to control the behavior.
  • Consider adding a config flag to control the behavior for multi-text-item messages, such as pick-last, pick-longest, concat, or separate-messages.
  • Review and test the proposed fix to ensure it covers both cases and does not introduce new issues.

Example

The proposed buildPostText function provides a starting point for the sanitization step:

function buildPostText(msg: AssistantMessage): string | null {
  if (msg.stopReason === 'error') return GENERIC_ERROR_FALLBACK; // or null to suppress
  const texts = (msg.content ?? []).filter(c => c.type === 'text' && c.text?.trim());
  if (texts.length === 0) return null;
  if (texts.length === 1) return texts[0].text;
  return texts[texts.length - 1].text; // pick-last; behind a config flag would be even better
}

Notes

The proposed fix focuses on the delivery-layer sanitization and does not address retry-with-backoff on transient provider errors, which is considered a separate feature.

Recommendation

Apply the proposed fix to implement the sanitization step in the delivery layer, as it addresses both issues and provides a single review surface and deploy.

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…

FAQ

Expected behavior

For stopReason=error:

  • Suppress the message entirely (admin-log server-side only), OR
  • Substitute a generic user-facing fallback (e.g., "Temporary issue — will retry shortly."), OR
  • Retry with backoff before posting
  • Never post the raw errorMessage verbatim to end users

For multi-text-item messages:

  • Select one text item to post (most useful: the last non-empty), OR
  • Expose a config flag: pick-last | pick-longest | concat (current) | separate-messages
  • concat should not be the default

Still need to ship something?

×6

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

Back to top recommendations

TRENDING