#21898: fix(telegram): auto-detect captionable messages for editMessageCaption
channel: telegram
size: M
Cluster:
Messaging Platform Improvements
## Summary
- **Problem:** When editing a Telegram message containing media (photo, video, audio, document, animation), OpenClaw calls `api.editMessageText()` — Telegram rejects this with `400: there is no text in the message to edit`
- **Why it matters:** Any `message(action=edit)` call on a captionable message silently fails with a 400 error, leaving the UI in an inconsistent state
- **What changed:** `editMessageTelegram` in `send.ts` now auto-detects captionable messages by catching the specific 400 and retrying with `editMessageCaption`; buttons-only updates use `editMessageReplyMarkup` directly
- **What did NOT change:** The generic `message` tool interface is unchanged — no new parameters, no Telegram-specific details exposed to callers; all other channel adapters untouched
## Change Type
- [x] Bug fix
## Scope
- [x] Integrations
## Linked Issue/PR
- Closes #
- Related #
## User-visible / Behavior Changes
`message(action=edit)` on messages containing photo, video, audio, document, or animation now succeeds instead of throwing a 400 error. No config or interface changes.
## Security Impact
- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `Yes`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
- **Explanation:** Two new Telegram Bot API methods are now called (`editMessageCaption`, `editMessageReplyMarkup`). Both are standard endpoints scoped to the bot's existing token — no new capabilities or data access beyond what `editMessageText` already had.
## Repro + Verification
### Environment
- OS: macOS Darwin 25.3.0 (arm64)
- Runtime/container: Node.js v22.22.0
- Model/provider: anthropic/claude-sonnet-4-6
- Integration/channel: Telegram
- Relevant config: Standard Telegram bot token
### Steps
1. Send a photo or video message via the `message` tool to a Telegram chat
2. Call `message(action=edit, messageId=..., message="updated caption")` on that message
3. Observe result
### Expected
Caption updates successfully on the media message
### Actual (before fix)
400: Bad Request: there is no text in the message to edit
## Evidence
- [x] Failing test/log before + passing after — 510/510 unit tests passing; 6 new tests added covering:
- Auto-detect retry path (`editMessageText` → catch → `editMessageCaption`)
- Buttons-only path (direct `editMessageReplyMarkup`)
- Error propagation (non-matching errors still throw)
- `MESSAGE_NOT_MODIFIED` swallowed as success on all paths
## Human Verification
- **Verified scenarios:** All three code paths via unit tests; `MESSAGE_NOT_MODIFIED` handling; HTML parse mode fallback preserved on both text and caption paths
- **Edge cases checked:** Non-matching 400 errors propagate normally; regex scoped tightly to the specific Telegram error string
- **What I did not verify:** Live end-to-end manual test with a real Telegram bot (unit tests mock the API layer)
## Compatibility / Migration
- Backward compatible? `Yes`
- Config/env changes? `No`
- Migration needed? `No`
## Failure Recovery
- **How to disable/revert:** Revert `src/telegram/send.ts` to previous `editMessageTelegram` implementation
- **Files/config to restore:** `src/telegram/send.ts` only
- **Known bad symptoms:** Unexpected retry loops on 400 errors — check `NO_TEXT_IN_MESSAGE_RE` regex against actual Telegram error wording
## Risks and Mitigations
- **Risk:** `NO_TEXT_IN_MESSAGE_RE` regex may not match if Telegram changes their error message wording
- **Mitigation:** Failure mode is graceful — unmatched errors propagate as before (old behavior), no new failure modes introduced
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes message editing failures for Telegram media messages (photo, video, audio, document, animation) by auto-detecting captionable messages and retrying with the correct API method.
**Key Changes:**
- Added `NO_TEXT_IN_MESSAGE_RE` regex to detect Telegram's "no text in message" error
- `editMessageTelegram` now catches the 400 error and retries with `editMessageCaption` for media messages
- Added direct `editMessageReplyMarkup` path for buttons-only updates (works for both text and media)
- Preserved HTML parse fallback behavior on both text and caption paths
- All three code paths properly handle `MESSAGE_NOT_MODIFIED` as success
**Test Coverage:**
Six new tests cover all code paths: auto-detect retry, buttons-only, error propagation, and `MESSAGE_NOT_MODIFIED` handling. Implementation is backward compatible with no API surface changes.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The implementation follows a defensive error-handling pattern with graceful fallbacks. The regex is scoped tightly to the specific Telegram error message. Six comprehensive tests cover all code paths including edge cases (MESSAGE_NOT_MODIFIED handling, error propagation, buttons-only updates). The change is backward compatible with no API surface modifications and only affects the Telegram channel adapter. Failure mode is graceful—unmatched errors propagate as before.
- No files require special attention
<sub>Last reviewed commit: 2e0852c</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22434: feat(telegram): support sending original quality images
by godenjan · 2026-02-21
82.2%
#21029: Feature/telegram bot avatar clean
by aleonnet · 2026-02-19
81.5%
#18915: fix(telegram): pass video width/height to sendVideo to prevent portra…
by storyarcade · 2026-02-17
80.5%
#19399: telegram: fix MEDIA false positives and partial final drop
by HOYALIM · 2026-02-17
80.0%
#20735: fix: skip auto-attaching tool MEDIA: paths already sent via message t…
by anillBhoi · 2026-02-19
79.9%
#19673: fix(telegram): avoid starting streaming replies with only 1-2 words
by emanuelst · 2026-02-18
79.7%
#19213: Telegram: preserve DM topic thread in direct replies
by Kemalau · 2026-02-17
79.3%
#12936: fix(telegram): omit message_thread_id for private DM chats
by omair445 · 2026-02-09
79.2%
#19479: fix(telegram): skip redundant final edit in partial streaming mode
by v8hid · 2026-02-17
79.0%
#7902: feat: Implement Telegram video note support with tests and docs
by thewulf7 · 2026-02-03
79.0%