Summary
The Telegram retry runner (createTelegramRetryRunner) is well-built but shouldRetry never fires for the most common transient failure class because the regex doesn't match grammY's HttpError message format.
Environment
- OpenClaw
2026.3.13
- Node 22, grammY, undici
- High-latency path (Malaysia → Amsterdam, ~530ms RTT)
Details
resolveTelegramShouldRetry checks error messages against:
const TELEGRAM_RETRY_RE = /429|timeout|connect|reset|closed|unavailable|temporarily/i;
grammY wraps underlying network errors in HttpError with the message:
Network request for 'sendMessage' failed!
This string contains none of the regex keywords. The actual error codes (ECONNRESET, UND_ERR_CONNECT_TIMEOUT, ETIMEDOUT) are in .cause, but formatErrorMessage only checks the top-level message.
Result: shouldRetry returns false. Retries never fire for network errors despite TELEGRAM_RETRY_DEFAULTS being correctly configured (3 attempts, 400ms base).
Observed log pattern (~40 failures/day)
[telegram] sendMessage failed: Network request for 'sendMessage' failed!
[telegram] block reply failed: HttpError: Network request for 'sendMessage' failed!
[telegram] message processing failed: HttpError: Network request for 'sendMessage' failed!
Suggested fix
Either:
formatErrorMessage should traverse .cause to include nested error codes/messages (cleaner, benefits all retry paths), OR
- Add
"Network request" to TELEGRAM_RETRY_RE (targeted fix)
Related: #17521 (locked, covers missing retry logic — this issue identifies why the existing retry logic doesn't fire)
Summary
The Telegram retry runner (
createTelegramRetryRunner) is well-built butshouldRetrynever fires for the most common transient failure class because the regex doesn't match grammY'sHttpErrormessage format.Environment
2026.3.13Details
resolveTelegramShouldRetrychecks error messages against:grammY wraps underlying network errors in
HttpErrorwith the message:This string contains none of the regex keywords. The actual error codes (
ECONNRESET,UND_ERR_CONNECT_TIMEOUT,ETIMEDOUT) are in.cause, butformatErrorMessageonly checks the top-level message.Result:
shouldRetryreturnsfalse. Retries never fire for network errors despiteTELEGRAM_RETRY_DEFAULTSbeing correctly configured (3 attempts, 400ms base).Observed log pattern (~40 failures/day)
Suggested fix
Either:
formatErrorMessageshould traverse.causeto include nested error codes/messages (cleaner, benefits all retry paths), OR"Network request"toTELEGRAM_RETRY_RE(targeted fix)Related: #17521 (locked, covers missing retry logic — this issue identifies why the existing retry logic doesn't fire)