Skip to content

Cron jobs: multiple delivery and scheduling bugs (channel resolution, non-default agents, silent failures) #17905

@tangopium

Description

@tangopium

Summary

Systematic testing of the cron job system uncovered multiple bugs affecting delivery, scheduling, and agent routing. These range from channel: "last" resolution failures to non-default agent jobs being silently skipped.

Environment

  • OpenClaw: 2026.2.14 (c1feda1)
  • OS: macOS (arm64)
  • Node: v25.4.0
  • Gateway: local, port 18789
  • Two agents configured: main (default) and a non-default agent with a separate workspace

Issue 1: channel: "last" fails when no chat channel history exists

Agents used exclusively via the web UI have no chat channel history. Since the web UI is a WebSocket client (not an outbound delivery adapter), it does not register as a channel. Any cron job using channel: "last" (which is the default for --announce) fails:

"cron delivery target is missing"

Steps to reproduce:

  1. Use an agent only via the web UI (never via Slack, WhatsApp, etc.)
  2. Create a cron job with --announce (which defaults to channel: "last")
  3. Job fails at delivery time with "cron delivery target is missing"

This is the most common failure path for users who only interact via the web UI.

Issue 2: channel: "last" resolves to wrong/unconfigured channels

When chat channel history exists, channel: "last" resolves to whatever channel was last used — even if that channel has since been removed or is unsupported:

  • After removing Slack, channel: "last" resolved to WhatsApp (from older history), producing: "Unsupported channel: whatsapp"
  • When Slack was still configured, channel: "last" resolved to Slack but delivery silently failed with channel_not_found (see Issue 3)

There is no validation that the resolved channel is actually functional.

Issue 3: Delivery failures are inconsistently handled

Delivery failures are silently swallowed in some cases but cause hard failures in others:

  • Default agent + channel: "last" → Slack: Job reports status: "ok" even though Slack delivery failed with channel_not_found. No error surfaced to the user.
  • Non-default agent + channel: "last" (no history): Job hard-fails with "cron delivery target is missing"
  • --best-effort-deliver works around both cases, but this flag is not the default

The inconsistency makes it difficult to diagnose delivery problems — jobs appear successful when they are not.

Issue 4: --session main --system-event skipped for non-default agents

# Works for main agent:
openclaw cron add --name "test-main" --agent main --system-event "Test" --session main --at 10s --delete-after-run
# → status: "ok"

# Fails for non-default agent:
openclaw cron add --name "test-secondary" --agent my-agent --system-event "Test" --session main --at 10s --delete-after-run
# → status: "skipped", error: "disabled", durationMs: ~25ms (never executed)

Even with --keep-after-run, the job is immediately skipped as "disabled". The scheduler log shows enabledCount: 0 at fire time despite the job being created with enabled: true.

Issue 5: Isolated announce summary routes to wrong agent session

openclaw cron add --name "test" --agent my-agent --message "Reply OK" --session isolated --announce --best-effort-deliver --at 10s --delete-after-run

The isolated run succeeds (status: "ok"), but:

  • The announce summary is not posted to agent:my-agent:main
  • Instead, the wakeMode: "now" heartbeat fires into session:agent:main:main (the default agent's session)
  • A separate agent:my-agent:cron:<jobId> session is created with the result

Gateway logs confirm the heartbeat targets the wrong session:

embedded run start: runId=... sessionId=<main-agent-session-id>... messageChannel=heartbeat

(The session ID belongs to agent:main:main, not the non-default agent's session)

Expected Behavior

  1. Cron jobs should not default to a delivery channel that requires chat history — web-UI-only users should have a working path out of the box
  2. channel: "last" should validate the resolved channel is functional before attempting delivery
  3. Delivery failures should always be surfaced (not silently swallowed) or --best-effort-deliver should be the default
  4. --session main --system-event jobs should execute for any agent, not just the default
  5. Isolated announce summaries should be posted to the cron job's own agent main session (agent:my-agent:main), not the default agent's session

Related Issues

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