NousResearch/hermes-agent
Retry logic for transient startup and TLS failures
Cluster 1526 · gateway. Data as of
Nothing open on GitHub. Fix merged in #1535 on 16 Mar 2026. Check it covers your case.
The short answer
0open issues
0open PRs
3items grouped
- Known?
- Yes. 3 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #1535. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #1535. That is separate from the fix event. - Still open
- Nothing open on GitHub.
These members address missing or insufficient retry behavior when transient TLS errors or other retryable failures occur during gateway startup and Telegram connection/send operations. Both the gateway restart and Telegram-specific TLS retry cases are represented.
Open issues0
Open PRs0
Fixes on record
-
#1535 fix(telegram): retry on transient TLS failures during connect and send
files:
gateway/platforms/telegram.pyShow the diff
-
gateway/platforms/telegram.py@@ -202,8 +202,26 @@ async def connect(self) -> bool: self._handle_media_message )) - # Start polling in background - await self._app.initialize() + # Start polling — retry initialize() for transient TLS resets + try: + from telegram.error import NetworkError, TimedOut + except ImportError: + NetworkError = TimedOut = OSError # type: ignore[misc,assignment] + _max_connect = 3 + for _attempt in range(_max_connect): + try: + await self._app.initialize() + break + except (NetworkError, TimedOut, OSError) as init_err: + if _attempt < _max_connect - 1: + wait = 2 ** _attempt + logger.warning( + "[%s] Connect attempt %d/%d failed: %s — retrying in %ds", + self.name, _attempt + 1, _max_connect, init_err, wait, + ) + await asyncio.sleep(wait) + else: + raise await self._app.start() loop = asyncio.get_running_loop() @@ -334,32 +352,47 @@ async def send( message_ids = [] thread_id = metadata.get("thread_id") if metadata else None + try: + from telegram.error import NetworkError as _NetErr + except ImportError: + _NetErr = OSError # type: ignore[misc,assignment] + for i, chunk in enumerate(chunks): - # Try Markdown first, fall back to plain text if it fails - try: - msg = await self._bot.send_message( - chat_id=int(chat_id), - text=chunk, - parse_mode=ParseMode.MARKDOWN_V2, - reply_to_message_id=int(reply_to) if reply_to and i == 0 else None, - message_thread_id=int(thread_id) if thread_id else None, - ) - except Exception as md_error: - # Markdown parsing failed, try plain text - if "parse" in str(md_error).lower() or "markdown" in str(md_error).lower(): - logger.warning("[%s] MarkdownV2 parse failed, falling back to plain text: %s", self.name, md_error) - # Strip MDV2 escape backslashes so the user doesn't - # see raw backslashes littered through the message. - plain_chunk = _strip_mdv2(chunk) - msg = await self._bot.send_message( - chat_id=int(chat_id), - text=plain_chunk, - parse_mode=None, # Plain text - reply_to_message_id=int(reply_to) if reply_to and i == 0 else None, - message_thread_id=int(thread_id) if thread_id else None, - ) - else: - raise # Re-raise if not a parse error + msg = None + for _send_attempt in range(3): + try: + # Try Markdown first, fall back to plain text if it fails + try: + msg = await self._bot.send_message( + chat_id=int(chat_id), + text=chunk, + parse_mode=ParseMode.MARKDOWN_V2, + reply_to_message_id=int(reply_to) if reply_to and i == 0 else None, + message_thread_id=int(thread_id) if thread_id else None, + ) + except Exception as md_error: + # Markdown parsing failed, try plain text + if "parse" in str(md_error).lower() or "markdown" in str(md_error).lower(): + logger.warning("[%s] MarkdownV2 parse failed, falling back to plain text: %s", self.name, md_error) + plain_chunk = _strip_mdv2(chunk) + msg = await self._bot.send_message( + chat_id=int(chat_id), + text=plain_chunk, + parse_mode=None, + reply_to_message_id=int(reply_to) if reply_to and i == 0 else None, + message_thread_id=int(thread_id) if thread_id else None, + ) + else: + raise + break # success + except _NetErr as send_err: + if _send_attempt < 2: + wait = 2 ** _send_attempt + logger.warning("[%s] Network error on send (attempt %d/3), retrying in %ds: %s", + self.name, _send_attempt + 1, wait, send_err) + await asyncio.sleep(wait) + else: + raise message_ids.append(str(msg.message_id)) return SendResult(
-
1 PR closed without merging
From the close comments: other 1
-
#1527 fix(telegram): retry on transient TLS failures during connect and send · other →
#1535
Closed issues · 1
- Closed#1526[Bug]: Telegram connection fails intermittently on startup due to transient TLS reset with no retry
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Subsystem
- gateway
- Merged PRs
- #1535
- Closed issues
- 1
- Attempts
- 1 PR closed without merging
- Fix link checked
- 16 Mar 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.