fix(claw): warn if gateway is running before migrating bot tokens

When hermes claw migrate copies Telegram/Discord/Slack bot tokens
from OpenClaw while the Hermes gateway is already polling with
those same tokens, the platforms conflict (e.g. Telegram 409
"terminated by other getUpdates request"). The gateway has runtime
detection for this, but the error only surfaces in logs and
gateway_state.json — users see their bot silently stop responding.

Two changes:

1. Pre-migration check in claw.py: reads gateway_state.json,
   verifies the PID is alive, and warns if platforms are connected.
   User can continue anyway or stop the gateway first.

2. Improved Telegram polling conflict message: mentions OpenClaw as
   a common cause and gives the restart command.

Refs #7907
This commit is contained in:
SHL0MS 2026-04-11 15:19:52 -04:00
parent dafe443beb
commit 23c7606251
2 changed files with 59 additions and 2 deletions

View file

@ -300,9 +300,11 @@ class TelegramAdapter(BasePlatformAdapter):
# Exhausted retries — fatal
message = (
"Another Telegram bot poller is already using this token. "
"Another process is already polling this Telegram bot token "
"(possibly OpenClaw or another Hermes instance). "
"Hermes stopped Telegram polling after %d retries. "
"Make sure only one gateway instance is running for this bot token."
"Only one poller can run per token — stop the other process "
"and restart with 'hermes start'."
% MAX_CONFLICT_RETRIES
)
logger.error("[%s] %s Original error: %s", self.name, message, error)

View file

@ -52,6 +52,57 @@ _OPENCLAW_SCRIPT_INSTALLED = (
# Known OpenClaw directory names (current + legacy)
_OPENCLAW_DIR_NAMES = (".openclaw", ".clawdbot", ".moldbot")
_GATEWAY_STATE_FILE = "gateway_state.json"
def _warn_if_gateway_running(hermes_home: Path, auto_yes: bool) -> None:
"""Check if a Hermes gateway is running with connected platforms.
Migrating bot tokens while the gateway is polling will cause conflicts
(e.g. Telegram 409 "terminated by other getUpdates request"). Warn the
user and let them decide whether to continue.
"""
import json
state_path = hermes_home / _GATEWAY_STATE_FILE
if not state_path.exists():
return
try:
data = json.loads(state_path.read_text())
except (json.JSONDecodeError, OSError):
return
# Check if the gateway PID is still alive
pid = data.get("pid")
if not pid:
return
try:
import os
os.kill(int(pid), 0)
except (ProcessLookupError, PermissionError, ValueError, TypeError):
return # stale state file, gateway not running
platforms = data.get("platforms") or {}
connected = [name for name, info in platforms.items()
if isinstance(info, dict) and info.get("state") == "connected"]
if not connected:
return
print()
print_error(
"Hermes gateway is running with active connections: "
+ ", ".join(connected)
)
print_info(
"Migrating bot tokens while the gateway is active will cause "
"conflicts (Telegram, Discord, and Slack only allow one active "
"session per token)."
)
print_info("Recommendation: stop the gateway first with 'hermes stop'.")
print()
if not auto_yes and not prompt_yes_no("Continue anyway?", default=False):
print_info("Migration cancelled. Stop the gateway and try again.")
sys.exit(0)
# State files commonly found in OpenClaw workspace directories that cause
# confusion after migration (the agent discovers them and writes to them)
_WORKSPACE_STATE_GLOBS = (
@ -252,6 +303,10 @@ def _cmd_migrate(args):
print_info(f"Workspace: {workspace_target}")
print()
# Check if a gateway is running with connected platforms — migrating tokens
# while the gateway is active will cause conflicts (e.g. Telegram 409).
_warn_if_gateway_running(hermes_home, auto_yes)
# Ensure config.yaml exists before migration tries to read it
config_path = get_config_path()
if not config_path.exists():