-
-
Notifications
You must be signed in to change notification settings - Fork 52.6k
Description
Summary
Cron jobs with delivery.mode: "announce", sessionTarget: "isolated", and explicit delivery.to (Slack channel ID) post results as thread replies instead of channel top-level messages. The isolated session inherits lastThreadId from prior conversation context, which leaks into the delivery path.
Steps to reproduce
- Have an agent converse in a Slack thread in channel
C0XXXXXXXXX - Session store records
lastThreadIdfrom that thread - A cron job fires with this config:
{
"sessionTarget": "isolated",
"delivery": {
"mode": "announce",
"channel": "slack",
"to": "C0XXXXXXXXX"
}
}- Observe where the result is posted
Expected behavior
The cron result is posted as a top-level message in the specified channel.
Actual behavior
The cron result is posted as a thread reply to a previous conversation thread in the same channel. The delivery status shows success — OpenClaw believes it delivered correctly.
OpenClaw version
2026.2.25
Operating system
Amazon Linux 2023 (aarch64)
Install method
npm global
Logs, screenshots, and evidence
No error logs — delivery reports success. The message simply arrives in the wrong location: a thread reply instead of channel top-level.
Impact and severity
- Affected: Any Slack user relying on cron announce delivery to a channel where the agent has prior thread context
- Severity: Medium (cron results are hidden in unrelated threads, easy to miss)
- Frequency: 100% repro when
delivery.tomatches the channel of a prior conversation thread - Consequence: Scheduled reports/notifications are buried in old threads instead of visible at channel top-level
Additional information
Root cause analysis:
Three layers combine to produce this bug:
-
session.ts—resolveCronSession(): WhenforceNew: true(isolated session), the new session entry is created via...entryspread, which preserveslastThreadId,lastTo,lastChannelfrom the prior session.forceNewonly resetssessionId, not delivery metadata. -
targets.ts—resolveSessionDeliveryTarget(): Whendelivery.tomatcheslastTo(same channel),lastThreadIdis adopted asthreadId(line ~152:mode !== "heartbeat" && channel === lastChannel ? lastThreadId : undefined). -
delivery-dispatch.ts:useDirectDeliveryistruewhenthreadId != null(line ~391), bypassing the announce flow and sending viadeliverViaDirectwiththread_tsset.
The fix likely belongs in (1): resolveCronSession should clear lastThreadId (and possibly lastTo, lastAccountId) when forceNew: true, since an isolated session should not inherit prior delivery routing state.
Related issues: #24176, #25450 (different symptoms in the same cron delivery area)
✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)