#Bug: Restart notification fails for Telegram DM topics

1 messages · Page 1 of 1 (latest)

robust forum
#

When using /restart from a Telegram DM topic, the gateway restart notification fails because it doesn't include a reply anchor (message_id).

Error: Telegram DM topic delivery requires a reply anchor; refusing to send outside the requested topic

Logs:

2026-05-30 23:44:35,132 WARNING gateway.run: Restart notification to telegram:XXXXXXXX was not delivered: Telegram DM topic delivery requires a reply anchor; refusing to send outside the requested topic
2026-05-30 23:44:35,132 WARNING gateway.run: Home-channel startup notification failed for telegram:XXXXXXXX: Telegram DM topic delivery requires a reply anchor; refusing to send outside the requested topic

Root cause: In gateway/run.py line ~10274, _handle_restart_command saves platform, chat_id, and thread_id to .restart_notify.json, but does NOT save event.message_id.

When _send_restart_notification (line ~14796) sends the notification, it uses metadata = {"thread_id": thread_id} but has no reply_to_message_id to include. Telegram's Bot API requires a reply anchor for DM topic messages.

stark ingot
#

This matches the current restart-notification routing path.

The restart command saves platform, chat id, and thread id, then the new gateway process replays only that thread id. For Telegram DM-topic lanes, synthetic sends need the DM-topic routing metadata rebuilt instead of sending with only thread_id.

There is already a PR for that path: https://github.com/NousResearch/hermes-agent/pull/34144

Until that lands in your installed build, the workaround is to disable restart/startup notifications for that Telegram setup or avoid using a DM-topic lane as the restart/home notification target.

cc @slow zodiac or @eager ocean (review?)

eager ocean
#

merged

#

@robust forum please run hermes update and test

robust forum
# eager ocean <@453378024079884291> please run `hermes update` and test

Thanks, I updated but noticed a couple of things:

  • /update is not streaming anymore in Telegram, but it wasn't before the update so it was not caused by the latest change.
  • /restart notification throws only the notif informing it will be restarted, but not the one informing after it was restarted and it keeps silent
stark ingot
#

Thanks, that means the original reply-anchor failure should be fixed in the updated code, but the missing “Gateway restarted successfully” message needs one fresh post-update log slice.

The /update streaming issue is a separate path, so let’s keep that separate for now.

For /restart, please run one fresh /restart from the same Telegram DM topic, then send the ~/.hermes/logs/gateway.log lines from just before the restart command through the gateway coming back online.

The key thing I’m looking for is whether the new run still says:

Telegram DM topic delivery requires a reply anchor

or whether it now says something different, like adapter not connected, notification suppressed, .restart_notify.json missing, or a different Telegram send error.

Also include your hermes --version output after the update so we can confirm the running install actually has the merged notification fix.

robust forum
#

@stark ingot Thanks. Here's what I found.

The original reply-anchor error is gone, no more "Telegram DM topic delivery requires a reply anchor." So that part is fixed.

But the notification now lands in the "All" (General) topic instead of the DM topic where /restart was issued. It sends successfully, just routes wrong, unless that is expected.

I dug into the code and here's what's happening: _thread_metadata_for_target builds metadata with telegram_dm_topic_reply_fallback and direct_messages_topic_id, but no reply_to_message_id since .restart_notify.json doesn't save message_id. _thread_kwargs_for_send then returns {"message_thread_id": None, "direct_messages_topic_id": <thread_id>}, but Telegram Bot API ignores direct_messages_topic_id for routing, so the message falls back to General (thread_id=1).

Logs:

2026-05-31 17:18:27,205 INFO gateway.run: Sent restart notification to telegram:XXXXXXXXX
2026-05-31 17:18:27,712 INFO gateway.run: Sent home-channel startup notification to telegram:XXXXXXXXX

No error in the log and it reports success, but the routing is wrong.

hermes --version post-update:
Hermes Agent v0.15.1 (2026.5.29)

Looks like what's actually needed is saving message_id in .restart_notify.json and using it as the reply anchor. direct_messages_topic_id alone doesn't cut it.

stark ingot
#

ok, let me take a look at making a fix for this. i've gotta force myself to use telegram more.

robust forum
#

Thanks, if anytime you need a PR just let me know, I can also test on my end. I know PRs need some additional time for verification so I prefer to report here when it seems urgent

stark ingot
#

Do you have working code that you can PR here?

#

if so, that can save me some time.

robust forum
#

Not for this issue

stark ingot
#

ok cool

#

I'll draft one up real quick and you can test?

robust forum
#

Sure thing

stark ingot
#

I put up a follow-up PR for the remaining Telegram DM-topic routing issue:

https://github.com/NousResearch/hermes-agent/pull/36139

This carries the original Telegram message id through the restart/update replay files, then uses it as the reply anchor when sending the post-restart or post-update notification. That should avoid the “sent successfully but landed in All / General” case from the current build.

If you can test that branch/build, the useful checks are:

  1. From the same Telegram DM topic, run /restart.
  2. Confirm the “Gateway restarted successfully” message lands in that same DM topic.
  3. If you’re comfortable testing update too, run /update from that same kind of DM topic and confirm progress/final update messages stay in the same topic.

The old hard error should still stay gone:

Telegram DM topic delivery requires a reply anchor

GitHub

What does this PR do?
Carries the triggering Telegram message id through gateway restart/update replay files so DM-topic notifications can be sent as anchored replies instead of relying on the anch...

#

Once you can confirm as well (I ran a few tests locally) then i'll ping for review

robust forum
#

Sure thing, I'll give it a try and will report back, thanks

robust forum
#

It works! Had to try a few restarts to make sure, but I noticed that this other message is still sent to the general feed instead of the topic:

⚠️ Gateway restarting — Your current task will be interrupted. Send any message after restart and I'll try to resume where you left off.

Not sure if that is expected to be separated, but the other two are now shown as expected

stark ingot
#

but... with that feedback, my system is already pushing another draft to that PR.

#

so if you want to test that, see if it is what you expect, lmk

robust forum
#

Todo is the all/general feed, while Sistema is just a topic I have for Hermes configuration

stark ingot
#

and that's with the commit from a min ago?

#

or the one from an hour ago?

robust forum
#

Those screenshots were while testing your PR, which I think it's up to the commit 3ef97a61b

stark ingot
#

yeah, i updated that pr with another commit.

#

to try and address the concerns you brought up

robust forum
#

So it means that the 4 different messages should be sent to the same topic where the restart was triggered? Or only the warning?

stark ingot
#

i'm trying to see if you've pulled the pr again in the last 8 min

#

because i changed things

robust forum
#

Nope, it was just the previous commit, not the recent one

stark ingot
#

ok. i've changed it ot try and address these things. same pr, new commit

robust forum
#

Ok let me try

stark ingot
#

specifically /restart

robust forum
#

Not sure if it's normal, but restarting from Telegram takes so long compared to the one from the terminal

#

I'll restart 2 times, one for applying the PR and the other to try the fix

stark ingot
#

hmm. not sure either. this is part of the code i dont exercise. i'm a discord guy with a terminal always open.

#

mm. ok, i'm testing myself and i dont like this new commit. you?

robust forum
#

That's fine maybe I can give Discord an opportunity 😅 If we can create threads like this in a Discord topic it would be really useful, having separate chats under the same topic, like projects in ChatGPT

stark ingot
#

i dont think my gateway is gunna restart now. this might be doing the old way that got rate limited all of the time. i'm looking into this more now

#

threads are a thing, yeah.

robust forum
#

Cool, I need to read the docs then

stark ingot
#

yeah... that looks like it takes way too long. I'm betting its getting rate limited or something.

robust forum
#

Yup, mine just finished, restarting again to check the fix

#

Looks like the message order was impacted, but it's still not visible in the topic

#

But I think having the restarted one at least is ok. Or maybe redundant messages can be unified

stark ingot
#

hmm.. you're getting different results than i am.

#

that's my all channel thread

#

the one above was in the channel topic i issued the command in

robust forum
#

And is still restarting

stark ingot
#

yeah, i'm going to look into that part too. the increased time should not be happening

#

and it looks like i have another commit from the ai. cool.

#

same pr new commit

#

though i dont know if i like what it did. hold up

#

ok, i'm moving back to local testing instead of having this thing add to a draft pr multiple times.

#

what's the desired behavior is what i need to know. i think we might have to push to all if the user did the restart from the terminal, etc. so i think what we're aiming for is not duplicating that and having it show in the thread or topic that you issue the command in?

robust forum
#

Ok, sharing some results

For the shutdown path (run.py ~line 3598), the home channel config doesn't have a source.message_id. A cache approach could work: store the last message_id when sending to the home channel, then use it as reply anchor during shutdown.

python
After adapter.send() to home channel:
result = await adapter.send(...)
if result and hasattr(result, 'message_id'):
self._home_channel_last_msg_id[(platform, chat_id, thread_id)] = result.message_id

In shutdown notification:

last_msg = self._home_channel_last_msg_id.get((platform, home.chat_id, home.thread_id))
metadata = self._thread_metadata_for_target(
    platform, home.chat_id, home.thread_id,
    reply_to_message_id=str(last_msg) if last_msg else None,
    adapter=adapter,
)
stark ingot
#

promising on the restart time part... now for the delivery part.

#

we were doing weird stuff there. some exit code thing for mac or something that was triggering a replace and a fallback delay thing that delayed it by like 300 seconds or more. this should be better. working on the other part.

stark ingot
#

ok, where i ran the command from and then my all channel. is this looking right?

#

startup also sends home-channel startup notifications after the targeted restart notification, but i think that might be a good thing. discord sends those to the home channel too.

robust forum
#

So you think that having these messages shown in both all and the topic in Telegram would be better? Otherwise, I think the approach in the screenshots is fine, less messages, more clarity

stark ingot
robust forum
stark ingot
#

if the user doesnt do anything in a topic and does it from a terminal, the telegram stuff should know about it somewhere. the home channel is prob good for that. it matches what discord does from what i can tell. i'm not trying to change a design, just fix what's confusing. i think there's maybe some utility there for people with different setups than what i have going on. not sure.

robust forum
#

You're right, I was forgetting that part. I'm now on the way to test the PR and confirm

stark ingot
#

man... think i found another edge case. restarting from the terminal shows the interrupt msg but not it coming back online. please hold off on testing. i'll fix this too.

#

ok, this makes more sense for from terminal restart. and maybe that means we can get rid of the home delivery for a telegram initiated restart and keep it in the topic or thread it was sent from.

robust forum
#

Ok then I'll hold on

stark ingot
#

should deliver to home if restart from the terminal and from the topic if from a topic and not to all.

stark ingot
# robust forum Ok then I'll hold on

let me know if you're able to test. i'd first do a manual gateway restart and ignore those restart msgs as something ran from the code in mem and then test from there.

robust forum
#

Ok let me try

robust forum
# stark ingot let me know if you're able to test. i'd first do a manual gateway restart and ig...

Very good news. Tested scenarios and results

  1. Idle /restart from Telegram (no active task)
  • Only "Gateway restarted successfully" sent — no scary interruption warning
  • Correct ✅
  1. /restart from Telegram with active task
  • Drain warning sent to active session topic AND home channel
  • Warning anchored to correct topic via reply
  • Gateway waited for task to finish, then restarted
  • Correct ✅
  1. Terminal restart (hermes gateway restart)
  • Drain warning to active session + home channel
  • "Gateway online" only to home channel (not to active session — no duplicate)
  • Auto-resume scheduled for interrupted sessions
  • Correct ✅
  1. Notification files
  • No leftover .restart_notify.json or .restart_pending.json after restart
  • Correct ✅

Minor suggestion: "Your current task will be interrupted" → "could be interrupted" — less alarming and more accurate since the drain waits for the task to finish.

Overall: Restart flow is noticeably faster from Telegram now. All scenarios pass.

stark ingot
#

Follow-up PR is ready for review:

https://github.com/NousResearch/hermes-agent/pull/36188

This cleans up the service-managed gateway restart path and the Telegram DM-topic notification routing around /restart.

Christian tested the updated PR from Telegram and confirmed the main restart cases now behave correctly:

Idle /restart from a Telegram DM topic only sends the “Gateway restarted successfully” message, in the right topic.

/restart with an active task sends the drain warning to the active session topic and home channel, anchors the topic warning correctly, waits for the task to finish, then restarts.

Terminal-triggered gateway restart sends the drain warning to active session + home channel, then sends the online notification only to the home channel, avoiding the duplicate active-session online ping.

The restart marker files also cleaned up afterward.

I’m leaving the suggested warning-copy tweak out of this PR since that wording predates this change and isn’t needed for the restart-flow fix.

cc @slow zodiac or @eager ocean (review?)

GitHub

What does this PR do?
Fixes planned gateway restart notifications across Telegram DM topics and service-managed restarts.
This PR keeps the existing crash-loop protection for real failures, but cha...