Skip to content

[Bug] Restart-sentinel continuation can get stuck after transient Telegram sendMessage failure #76087

Description

@richardmqq

Summary

Restart-sentinel continuation delivery can become stuck in ~/.openclaw/session-delivery-queue/ after a transient Telegram sendMessage network failure. The continuation entry is persisted and retry metadata is updated, but there appears to be no periodic/session wake recovery after the immediate startup drain fails, so the user never receives the post-restart continuation/report until another gateway startup happens.

This is related to Telegram transport flakiness / delivery durability, but distinct from ordinary outbound message queue recovery: restart continuation uses the session-delivery queue in server-restart-sentinel, and a failed immediate drain remains pending without an automatic follow-up retry.

Environment

  • OpenClaw: 2026.4.29 (a448042)
  • Host: macOS 26.4.1 arm64, Node 25.9.0
  • Channel: Telegram long-poll bot mode
  • Surface: restart-sentinel continuation for agent:system-architect:telegram:direct:<user>

Observed evidence

Gateway log:

2026-05-02T21:16:03.924+08:00 [restart-sentinel] restart continuation: retry failed for entry 5bfb077fa406f9dad97b2a82488f95bef182e9ae4f9672620de895622f578052: Network request for 'sendMessage' failed!

The entry remained pending afterwards:

{
  "kind": "agentTurn",
  "sessionKey": "agent:system-architect:telegram:direct:<user>",
  "message": "Post-restart continuation ...",
  "route": {
    "channel": "telegram",
    "to": "telegram:<user>",
    "accountId": "system-architect",
    "chatType": "direct"
  },
  "id": "5bfb077fa406f9dad97b2a82488f95bef182e9ae4f9672620de895622f578052",
  "enqueuedAt": 1777727345013,
  "retryCount": 1,
  "lastAttemptAt": 1777727763925,
  "lastError": "Network request for 'sendMessage' failed!"
}

The entry was still present at:

~/.openclaw/session-delivery-queue/5bfb077fa406f9dad97b2a82488f95bef182e9ae4f9672620de895622f578052.json

During the same day the Telegram channel had intermittent transport failures, but later openclaw status --deep reported Telegram OK, so this is a transient-send/recovery problem rather than a permanent token/config failure.

Examples from the same day:

2026-05-02T13:44:10+08:00 [telegram] ... Network request for 'getUpdates' failed!
2026-05-02T16:02:34+08:00 [telegram] Polling stall detected ... Network request for 'getUpdates' failed!
2026-05-02T18:12:28+08:00 [telegram] Polling stall detected ... Network request for 'getUpdates' failed!
2026-05-02T21:16:03+08:00 [restart-sentinel] restart continuation: retry failed ... Network request for 'sendMessage' failed!

Source-code trace

Installed dist paths on 2026.4.29:

  • dist/server-restart-sentinel-_OFhLVvA.js
  • dist/hook-client-ip-config-BCNYpeHn.js

Relevant flow:

  1. scheduleRestartSentinelWake() loads the restart sentinel at gateway startup.
  2. loadRestartSentinelStartupTask() enqueues a restart continuation via enqueueSessionDelivery(buildQueuedRestartContinuation(...)).
  3. It then calls drainRestartContinuationQueue({ entryId }).
  4. drainRestartContinuationQueue() calls drainPendingSessionDeliveries(... selectEntry: entry.id === entryId, bypassBackoff: true).
  5. If deliverQueuedSessionDelivery() throws (Telegram sendMessage network failure), drainQueuedEntry() calls failSessionDelivery(), increments retryCount, stores lastError, and leaves the JSON in session-delivery-queue/.
  6. recoverPendingRestartContinuationDeliveries() exists, but startup wiring in activateGatewayScheduledServices() only calls recoverPendingSessionDeliveries() once after startup (setTimeout(..., 1250)), not periodically.

So if the immediate startup continuation drain fails after that startup recovery window, the entry remains pending until the next gateway startup (or manual intervention).

Expected behavior

Restart continuation delivery should be durable and eventually delivered after transient Telegram/network failures, without requiring another gateway restart.

At minimum:

  • Pending restart continuation entries should be retried after their backoff expires.
  • Retries should continue up to the existing max retry limit (retryCount >= 5).
  • Permanent delivery errors (e.g. 400 chat not found / thread not found) should be moved to failed with clear diagnostics.
  • Transient transport errors should not leave the restart continuation invisible to the user.

Actual behavior

A transient Telegram sendMessage network failure leaves the restart continuation pending in session-delivery-queue/ with retryCount: 1, but no automatic retry occurs during normal gateway operation. The user sees no post-restart continuation/report.

Impact

This weakens the safety of the new gateway restart runner. The runner correctly writes a sentinel and enqueues continuation, but a single transient Telegram send failure can make the continuation appear lost. That pushes operators back toward manual checking and makes protected restart workflows less reliable.

Suggested fix

Add periodic/backoff-based recovery for session-delivery queue entries, similar in spirit to outbound delivery recovery.

Possible implementation options:

  1. Start a lightweight scheduled recovery loop for recoverPendingRestartContinuationDeliveries() after gateway startup, e.g. every 30-60s, respecting isSessionDeliveryEligibleForRetry() and max retries.
  2. Or, after drainRestartContinuationQueue() fails an entry, schedule a one-shot retry timer for that entry's next backoff deadline.
  3. Add status visibility for pending/failed session-delivery queue entries in openclaw status --deep or a diagnostic command.
  4. Consider aligning restart continuation queue behavior with the normal outbound delivery-queue recovery behavior, while preserving idempotency via the existing idempotencyKey.

Related

Possibly related but not identical:

This issue is specifically about restart-sentinel session-delivery retry scheduling after a transient sendMessage failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions