Summary
A one-shot cron job created via the cron tool with delivery.channel: "last" fails at delivery time because the "last route" resolves to @heartbeat (an internal session target) instead of the actual Telegram chat the user was communicating from when the job was created.
Environment
- OpenClaw: 2026.3.13
- Channel: Telegram (direct chat)
- OS: NixOS (Docker deployment)
Steps to Reproduce
- Chat with the agent via Telegram DM
- Ask the agent to create a one-shot cron reminder (e.g. "remind me to pick up a parcel at 12:00")
- The agent creates a cron job with
delivery.channel: "last" (a documented, valid value)
- When the job fires, delivery fails
Job Configuration (from jobs.json)
{
"id": "3ec504b7-9238-43c6-b8c3-8cc4507f6a2a",
"name": "reminder-pickup-parcel-once",
"schedule": { "kind": "at", "at": "2026-03-14T04:00:00.000Z" },
"sessionTarget": "isolated",
"delivery": {
"mode": "announce",
"channel": "last"
},
...
}
Error
Error: Telegram recipient @heartbeat could not be resolved to a numeric chat ID
(Call to 'getChat' failed! (400: Bad Request: chat not found))
Expected Behavior
delivery.channel: "last" should resolve to the Telegram chat where the user was interacting when the cron job was created — in this case, the DM chat with numeric ID 715441687.
Actual Behavior
The "last route" resolves to @heartbeat, which is an internal session concept, not a valid Telegram recipient. The Telegram getChat API call fails with 400.
Analysis
- The agent's tool call is correct —
"last" is explicitly documented as a valid value for delivery.channel.
- The issue appears to be in the "last route" resolution logic: by the time the deferred cron job executes, the session's last delivery target has been overwritten by an internal heartbeat session, losing the original Telegram chat context.
- A similar cron job with an explicit
delivery.channel: "telegram" and delivery.to: "715441687" works correctly.
Related Issues
Workaround
Use explicit delivery.channel and delivery.to with numeric chat IDs instead of relying on "last".
Summary
A one-shot cron job created via the cron tool with
delivery.channel: "last"fails at delivery time because the "last route" resolves to@heartbeat(an internal session target) instead of the actual Telegram chat the user was communicating from when the job was created.Environment
Steps to Reproduce
delivery.channel: "last"(a documented, valid value)Job Configuration (from
jobs.json){ "id": "3ec504b7-9238-43c6-b8c3-8cc4507f6a2a", "name": "reminder-pickup-parcel-once", "schedule": { "kind": "at", "at": "2026-03-14T04:00:00.000Z" }, "sessionTarget": "isolated", "delivery": { "mode": "announce", "channel": "last" }, ... }Error
Expected Behavior
delivery.channel: "last"should resolve to the Telegram chat where the user was interacting when the cron job was created — in this case, the DM chat with numeric ID715441687.Actual Behavior
The "last route" resolves to
@heartbeat, which is an internal session concept, not a valid Telegram recipient. The TelegramgetChatAPI call fails with 400.Analysis
"last"is explicitly documented as a valid value fordelivery.channel.delivery.channel: "telegram"anddelivery.to: "715441687"works correctly.Related Issues
deliveryContextmissingtofieldcron.defaults.delivery(would provide a workaround)Workaround
Use explicit
delivery.channelanddelivery.towith numeric chat IDs instead of relying on"last".