hermes - 💡(How to fix) Fix macOS: Telegram gateway lock always has start_time=null, causing PID reuse false positives

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

ERROR [Telegram] Telegram bot token already in use (PID ). Stop the other gateway first. except Exception:

Root Cause

On macOS, _get_process_start_time() in gateway/status.py always returns None because it reads from /proc/<pid>/stat, which only exists on Linux. As a result, the Telegram bot token scoped lock file always records "start_time": null.

RAW_BUFFERClick to expand / collapse

Bug

On macOS, _get_process_start_time() in gateway/status.py always returns None because it reads from /proc/<pid>/stat, which only exists on Linux. As a result, the Telegram bot token scoped lock file always records "start_time": null.

When the gateway crashes or exits without cleaning up the lock file, the stale detection logic falls back to os.kill(pid, 0). If another unrelated process later reuses the same PID (e.g. a system app), it is mistakenly treated as a live Hermes gateway. The lock is never cleared, and the new gateway fails to connect to Telegram with:

ERROR [Telegram] Telegram bot token already in use (PID ). Stop the other gateway first.

The only recovery is to manually delete the stale lock file at: ~/.local/state/hermes/gateway-locks/telegram-bot-token-*.lock

Root cause

_get_process_start_time() has no macOS fallback. On macOS, start_time is always null in lock records, so the PID-reuse guard never activates.

Fix

Add a macOS fallback using ps -p <pid> -o lstart= and parse the output to an epoch integer:

def _get_process_start_time(pid: int) -> Optional[int]:
    # Linux: read from /proc filesystem
    stat_path = Path(f"/proc/{pid}/stat")
    try:
        return int(stat_path.read_text().split()[21])
    except (FileNotFoundError, IndexError, PermissionError, ValueError, OSError):
        pass

    # macOS fallback: parse lstart from ps
    try:
        import subprocess
        from datetime import datetime
        out = subprocess.check_output(
            ["ps", "-p", str(pid), "-o", "lstart="],
            stderr=subprocess.DEVNULL,
            text=True,
        ).strip()
        if out:
            normalized = " ".join(out.split())
            dt = datetime.strptime(normalized, "%a %b %d %H:%M:%S %Y")
            return int(dt.timestamp())
    except Exception:
        pass

    return None

Environment

- macOS 15.4
- Python 3.11

---

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING