-
-
Notifications
You must be signed in to change notification settings - Fork 39.7k
Description
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:
- Use an agent only via the web UI (never via Slack, WhatsApp, etc.)
- Create a cron job with
--announce(which defaults tochannel: "last") - 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 withchannel_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 reportsstatus: "ok"even though Slack delivery failed withchannel_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-deliverworks 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-runThe isolated run succeeds (status: "ok"), but:
- The announce summary is not posted to
agent:my-agent:main - Instead, the
wakeMode: "now"heartbeat fires intosession: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
- 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
channel: "last"should validate the resolved channel is functional before attempting delivery- Delivery failures should always be surfaced (not silently swallowed) or
--best-effort-delivershould be the default --session main --system-eventjobs should execute for any agent, not just the default- 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
- fix(cron): use requested agentId for isolated job auth resolution #13983 — "Cron: use requested agentId for isolated job auth resolution" (partially addressed auth, but main-session routing still broken)
- fix(cron): pass agentId to runHeartbeatOnce for main-session jobs #14140 — "Cron: pass agentId to runHeartbeatOnce for main-session jobs" (appears to not fully fix the routing for non-default agents)
- [Bug]: Cron job announce delivery ignores configured channel, routes to unconfigured whatsapp #13420 — "Cron job announce delivery ignores configured channel, routes to unconfigured whatsapp" (related delivery routing bugs)
- Reminders not working: blocked when heartbeat disabled #4224 — "Reminders not working: blocked when heartbeat disabled" (empty HEARTBEAT.md blocks cron delivery)
- fix(cron): share isolated announce flow + harden cron scheduling/delivery #11641 — "Share isolated announce flow and harden cron scheduling/delivery" (prior hardening effort)
- Usage tracking broken for setup-token auth (missing user:profile scope) #4614 — "setup-token only requests user:inference scope, missing user:profile" (OAuth scope issue affecting usage display)