Skip to content

[Bug]: Cron announce delivery inherits session lastThreadId — delivers into active Slack thread instead of top-level DM #25730

@markshields-tl

Description

@markshields-tl

Summary

When a cron job with delivery.mode: "announce" fires while the main session is actively replying inside a Slack thread, the delivery inherits lastThreadId from the session and sends the cron output into the active thread instead of the top-level DM.

This causes unrelated content (research reports, reminders, proactive cron output) to appear inside whichever thread happens to be active at the moment — confusing and disruptive.

Root cause

resolveSessionDeliveryTarget() in targets.ts unconditionally inherits lastThreadId when the channel matches:

const threadId = channel && channel === lastChannel ? lastThreadId : void 0;
// ...
const resolvedThreadId = explicitThreadId ?? threadId;

The heartbeat/cron delivery path calls this via resolveHeartbeatDeliveryTarget() with mode: "heartbeat", but resolveSessionDeliveryTarget does not use this mode to suppress lastThreadId fallback.

Steps to reproduce

  1. Configure a cron job with delivery.mode: "announce", delivery.channel: "slack", delivery.to: "user:<userId>"
  2. Start a conversation in a Slack thread (reply to any message)
  3. Wait for the cron job to fire while the thread conversation is active
  4. Observe: cron output appears inside the active thread instead of top-level DM

Expected behavior

Cron announce delivery should send to the top-level DM channel, ignoring any active lastThreadId from the session. Thread targeting should only happen when explicitly configured (e.g., the proposed C12345:thread:TS syntax from #19903).

Suggested fix

In resolveSessionDeliveryTarget(), skip lastThreadId fallback when mode === "heartbeat":

const threadId = (params.mode !== "heartbeat" && channel && channel === lastChannel) 
  ? lastThreadId 
  : void 0;

This is a one-line change. The function already receives the mode parameter — it just needs to use it.

Environment

  • OpenClaw version: 2026.2.23 (also present in 2026.2.22-2)
  • Channel: Slack (Socket Mode)
  • Cron job config: sessionTarget: "isolated", delivery.mode: "announce", delivery.to: "user:<id>"

Related

AI-Assisted Disclosure

This issue was filed by an AI assistant (Claude, via OpenClaw). The root cause analysis was performed by reading the minified source in dist/reply-*.js and tracing the delivery flow through resolveHeartbeatDeliveryTargetresolveSessionDeliveryTarget. The author (human operator) understands the issue and has experienced it repeatedly in production.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions