openclaw - ✅(Solved) Fix [Bug] Telegram channel occasionally injects blank user messages, causing API errors [2 pull requests, 5 comments, 4 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#74137Fetched 2026-04-30 06:28:03
View on GitHub
Comments
5
Participants
4
Timeline
9
Reactions
0
Author
Timeline (top)
commented ×5cross-referenced ×3referenced ×1

Error Message

Telegram channel occasionally injects empty/blank user messages into the session, which causes the LLM provider API to reject the request with an error like: Gateway error log (gateway.err.log): 2026-04-29T14:11:57.869+08:00 [agent/embedded] embedded run agent end: runId=9aa02983-dca1-44dd-86e5-6ddc1e0fcaaa isError=true model=gpt-5.5 provider=openai-codex error=One of "input" or "previous_response_id"or 'prompt'or 'conversation_id' must be provided. Session trajectory shows the user message content is empty string "" when the error occurs. Self-repair mechanism kicks in after the error: The self-repair correctly drops the blank message, but the error has already been surfaced to the user via Telegram before the repair runs.

  • The error is transient — after self-repair, the session continues normally
  • When the error occurs, the failover chain also triggers (tries multiple providers), all failing with the same empty-messages issue (e.g., messages must contain at least one entry for Claude /messages requests, The messages parameter is illegal from zai provider)

Fix Action

Fixed

PR fix notes

PR #74121: fix: Drop blank user messages; skip toolless fallbacks

Description (problem / solution / changelog)

Summary

Fix /new cascading failure where a blank user message in a fresh session triggers a 422, gets misclassified as a format failover, cools down the shared auth profile, and burns every fallback (including a tool-incapable deepseek-r1:14b) before surfacing a generic error to the user.

Four narrow changes, all defense-in-depth:

  • In-memory blank-user-message drop in sanitizeSessionHistory (src/agents/pi-embedded-runner/replay-history.ts). The on-disk repairSessionFileIfNeeded already dropped blank user entries pre-flight, but a blank appended in-memory between disk-repair and dispatch (or written by any path that bypasses the chat-send guard) reached the model unchecked. Predicate is now shared with on-disk repair via the new src/agents/blank-user-message.ts helper — single source of truth.

  • format failures no longer cool down auth profiles (src/agents/pi-embedded-runner/run/auth-profile-failure-policy.ts). HTTP 422 / "invalid request format" reflects a malformed payload we sent — it's a client-side bug, not provider auth health. Cooling the profile blocked sibling models that share it (e.g. claude-opus-4-7 after claude-opus-4-6 failed). Mirrors the existing classification in shouldPreserveTransientCooldownProbeSlot.

  • Tool-capability filter in fallback chain (src/agents/model-fallback.ts, src/agents/agent-command.ts). When requiresTools: true (always true for the embedded agent path), fallback entries whose model definition has compat.supportsTools === false are skipped with a warn log. Reuses the existing supportsModelTools helper. The user's explicit primary is always kept regardless.

  • Refactor: repairUserEntryWithBlankTextContent in session-file-repair.ts now consumes the shared content predicate instead of duplicating it.

/new itself is innocent — it writes only a session header to disk (src/gateway/session-reset-service.ts:649-661). I considered rejecting empty strings at sanitizeChatSendMessageInput but the existing chat handler check at chat.ts:1898 ("message or attachment required") already covers the no-attachments case, and rejecting empty at the sanitizer breaks the legitimate attachment-only flow (handles chat send and history flows test).

Test plan

  • pnpm test src/agents/blank-user-message.test.ts — 10 new pure-helper cases
  • pnpm test src/agents/pi-embedded-runner.sanitize-session-history.test.ts — adds in-memory blank-drop and no-warn-on-clean-history cases (57 total passing)
  • pnpm test src/agents/pi-embedded-runner/run/auth-profile-failure-policy.test.ts — adds format exemption case
  • pnpm test src/agents/model-fallback.test.ts — adds two tool-capability-filter cases (one filtering deepseek-r1:14b, one keeping fallbacks with unknown tool support)
  • pnpm test src/agents/session-file-repair.test.ts — refactor preserves on-disk repair behavior
  • pnpm test src/agents/auth-profiles — 161 passing, no cooldown semantics regressions
  • pnpm check:changed — typecheck core + core-tests, lint, import-cycles, all guard scripts green
  • pnpm test:changed — 18 shards, 3589 passed / 1 skipped / 0 failed

Changed files

  • src/agents/agent-command.ts (modified, +5/-0)
  • src/agents/model-fallback.test.ts (modified, +91/-0)
  • src/agents/model-fallback.ts (modified, +36/-0)
  • src/agents/pi-embedded-runner/run/auth-profile-failure-policy.test.ts (modified, +14/-0)
  • src/agents/pi-embedded-runner/run/auth-profile-failure-policy.ts (modified, +11/-1)

PR #74168: fix(agents): add last-chance guard for blank user prompts in embedded runner

Description (problem / solution / changelog)

Summary

Fixes #74137

Adds a last-chance guard in the embedded runner that prevents blank visible user prompts from being submitted to the LLM provider API. This catches blank messages that slip past earlier ingress guards (e.g. Telegram body parsing, hasUserBody check) due to envelope wrapping or intermittent channel edge cases.

Problem

Telegram (and occasionally WeChat) channels can intermittently inject blank/empty user messages into sessions. While several upstream guards exist (Telegram body parsing, hasUserBody in get-reply-run.ts, replay sanitization, session file repair), the embedded runner's existing prompt submission guard (hasPromptSubmissionContent) passes blank prompts when there is existing session history (messages.length > 0). The blank prompt reaches the provider API and is rejected:

One of "input" or "previous_response_id" or "prompt" must be provided.

The session self-repair mechanism drops blank messages afterward, but the error has already been surfaced to the user.

Solution

  • Extract isBlankUserPromptSubmission() helper into attempt.prompt-helpers.ts — detects blank visible prompts on non-runtimeOnly turns without images
  • Add a last-chance guard in attempt.ts before prompt submission that skips blank user prompts even when session history exists
  • RuntimeOnly prompts (memory flush, heartbeats, system events) are intentionally excluded — they use empty visible prompts by design
  • Session file repair remains as a safety net for any persisted blank messages

Changes

  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts — new isBlankUserPromptSubmission() helper
  • src/agents/pi-embedded-runner/run/attempt.ts — last-chance guard using the helper
  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts — 5 new tests covering blank detection, image bypass, runtimeOnly exclusion

Testing

All ClawSweeper acceptance criteria pass:

  • pnpm test src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts (13 tests)
  • pnpm test src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts (23 tests)
  • pnpm test src/auto-reply/reply/get-reply-run.media-only.test.ts (39 tests)
  • pnpm test extensions/telegram/src/bot-message-context.body.test.ts (5 tests)
  • pnpm test src/agents/session-file-repair.test.ts (11 tests)

Changed files

  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts (modified, +39/-0)
  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts (modified, +14/-0)
  • src/agents/pi-embedded-runner/run/attempt.ts (modified, +28/-0)

Code Example

One of "input" or "previous_response_id" or "prompt" or "conversation_id" must be provided.

---

2026-04-29T14:11:57.869+08:00 [agent/embedded] embedded run agent end: runId=9aa02983-dca1-44dd-86e5-6ddc1e0fcaaa isError=true model=gpt-5.5 provider=openai-codex error=One of "input" or "previous_response_id"or 'prompt'or 'conversation_id' must be provided.

---

2026-04-29T14:12:10.960+08:00 [agent/embedded] session file repaired: rewrote 1 assistant message(s), dropped 1 blank user message(s) (4b225235-e5b7-4589-984c-507af857308e.jsonl)
RAW_BUFFERClick to expand / collapse

Bug Description

Telegram channel occasionally injects empty/blank user messages into the session, which causes the LLM provider API to reject the request with an error like:

One of "input" or "previous_response_id" or "prompt" or "conversation_id" must be provided.

Environment

  • OS: macOS (arm64), Darwin 25.3.0
  • OpenClaw version: 2026.4.26
  • Channel: Telegram (direct message)
  • Primary model: openai-codex/gpt-5.5

Steps to Reproduce

  1. Use OpenClaw with Telegram channel in direct message mode
  2. Send messages normally over time
  3. Occasionally (seemingly at random), a blank user message is injected into the session
  4. The blank message is sent to the LLM API, which rejects it

Observed Behavior

Gateway error log (gateway.err.log):

2026-04-29T14:11:57.869+08:00 [agent/embedded] embedded run agent end: runId=9aa02983-dca1-44dd-86e5-6ddc1e0fcaaa isError=true model=gpt-5.5 provider=openai-codex error=One of "input" or "previous_response_id"or 'prompt'or 'conversation_id' must be provided.

Session trajectory shows the user message content is empty string "" when the error occurs.

Self-repair mechanism kicks in after the error:

2026-04-29T14:12:10.960+08:00 [agent/embedded] session file repaired: rewrote 1 assistant message(s), dropped 1 blank user message(s) (4b225235-e5b7-4589-984c-507af857308e.jsonl)

The self-repair correctly drops the blank message, but the error has already been surfaced to the user via Telegram before the repair runs.

Expected Behavior

Blank/empty messages from Telegram should be silently dropped before they are written to the session file and sent to the LLM API. The self-repair is a good safety net, but the blank message should never reach the API in the first place.

Additional Context

  • This has occurred multiple times across different sessions (also seen in WeChat channel sessions)
  • The error is transient — after self-repair, the session continues normally
  • When the error occurs, the failover chain also triggers (tries multiple providers), all failing with the same empty-messages issue (e.g., messages must contain at least one entry for Claude /messages requests, The messages parameter is illegal from zai provider)
  • A pending gateway restart was blocked for 4+ minutes due to active task runs, which may be related to session recovery timing

extent analysis

TL;DR

Filter out empty user messages before sending them to the LLM API to prevent rejection due to missing required parameters.

Guidance

  • Investigate the Telegram channel integration to determine why empty messages are being injected into the session.
  • Implement a check to silently drop empty messages before they are written to the session file and sent to the LLM API.
  • Review the self-repair mechanism to ensure it is correctly handling dropped messages and preventing them from being resent.
  • Consider adding logging to track when empty messages are dropped to help identify the root cause of the issue.

Example

if user_message != "":
    # Send the message to the LLM API
    send_to_llm_api(user_message)
else:
    # Silently drop the empty message
    logger.info("Dropped empty user message")

Notes

The root cause of the empty messages is unclear, and further investigation is needed to determine why they are being injected into the session. The self-repair mechanism is correctly handling the dropped messages, but it would be better to prevent them from being sent to the LLM API in the first place.

Recommendation

Apply a workaround to filter out empty user messages before sending them to the LLM API, as this will prevent the error from occurring and improve the overall user experience.

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 [Bug] Telegram channel occasionally injects blank user messages, causing API errors [2 pull requests, 5 comments, 4 participants]