Skip to content

HEARTBEAT_OK leaks to Telegram DM despite showOk: false #17646

Description

@parkerati

Description

HEARTBEAT_OK messages are being delivered to Telegram DMs despite channels.telegram.heartbeat.showOk being explicitly set to false (which is also the default value).

Config

{
  "channels": {
    "telegram": {
      "heartbeat": {
        "showOk": false
      }
    }
  }
}

Expected behavior

When showOk: false, HEARTBEAT_OK acknowledgments should be suppressed and never delivered to Telegram. Per the docs: "By default, HEARTBEAT_OK acknowledgments are suppressed while alert content is delivered."

Actual behavior

HEARTBEAT_OK messages are intermittently delivered to Telegram DMs. Observed 3 leaked messages in a single evening session. The leak is intermittent — not every heartbeat cycle leaks, but multiple do.

Environment

  • OpenClaw version: 2026.2.13
  • Channel: Telegram (bot, DM)
  • Heartbeat interval: default (30m)
  • Stream mode: partial
  • Group config: One allowlisted group with requireMention: false
  • OS: macOS (Darwin 24.6.0, x64)
  • Node: v22.22.0

Investigation notes

  • Verified resolveHeartbeatVisibility() in heartbeat-visibility-CEj2dtuo.js correctly resolves showOk: false from the config chain (perAccount → perChannel → channelDefaults → built-in default).
  • The heartbeat runner in health-DUYdoLkQ.js checks canAttemptHeartbeatOk = Boolean(visibility.showOk && ...) which should be false.
  • When shouldSkipMain is true and canAttemptHeartbeatOk is false, no delivery should occur.
  • Gateway logs show only [heartbeat] started entries (~10s intervals, likely scheduler loop) with no outcome/result logging, making it difficult to trace the delivery path.
  • The showOk: false default means this should work out of the box without any explicit config.

Reproduction

  1. Configure Telegram channel with default heartbeat settings (or explicit showOk: false)
  2. Let heartbeats run for several hours
  3. Observe intermittent HEARTBEAT_OK messages appearing in Telegram DM

Possible leads

  • Could be related to streamMode: "partial" interaction with heartbeat reply path
  • Could be a race condition in the reply dispatch pipeline where the heartbeat response leaks through the normal session reply path before the heartbeat suppression logic runs
  • The stripping logic in normalizeStreamingText skips HEARTBEAT_OK when params.isHeartbeat is true (to let the heartbeat system handle it), but if there is a secondary dispatch path, it could leak

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions