Skip to content

chore: typed error for cron delivery.channel="last" when no prior chat exists #80984

Description

@esqandil

Follow-up to a forthcoming PR that introduces a typed WebchatNotDeliverableError thrown from resolveMessageChannelSelection for delivery.channel: "webchat" (the internal session-bound surface, not a deliverable channel plugin).

The cron delivery resolver (resolveDeliveryTarget in src/cron/jobs.ts, calling into src/infra/outbound/channel-selection.ts) has a sibling failure family that surfaces the same generic wrapped error string — "Channel is required (no configured channels detected). Set delivery.channel explicitly or use a main session with a previous channel." — but for a different root cause:

  • delivery.channel: "last" (or omitted) when the resolved session key has no prior chat in the session store to anchor against.

Today both failure modes wrap to the same string at assertSupportedJobSpec / the cron-runner delivery resolver, which makes them indistinguishable in task_runs.error and in openclaw cron list output (e.g. announce -> last (last -> no route, will fail-closed: Channel...)). Operators have to read cron show <id> and cross-reference session state to tell whether they configured a bad channel or just have a fresh session with no chat history.

Proposal

Add a parallel typed error (working name: NoPriorChatChannelError) thrown from the same resolveMessageChannelSelection site (or from the cron-side resolveDeliveryTarget if that is the cleaner seam) when:

  1. params.channel normalizes to "last" (or is undefined/empty meaning "infer from session history"), AND
  2. the resolved session entry has no lastChannel recorded, AND
  3. there is no params.fallbackChannel resolvable.

Message should name the actionable fixes: configure a real channel and switch delivery.channel to it explicitly, or use sessionTarget: "session:agent:<id>:main" with payload.kind: "agentTurn" and delivery.mode: "none" so the agent turn output renders in its own session without an announce route.

Why not include in the original PR

To keep the original diff focused. The webchat case is structurally non-deliverable (a property of the channel constant); the "last" case is dependent on session state at fire time (a property of the session store). Different invariants, different message text, and the "last" case probably wants its own test fixtures around stale/empty session history.

Source pointers (paths at the time of filing)

  • src/utils/message-channel-constants.tsINTERNAL_MESSAGE_CHANNEL, WebchatNotDeliverableError (introduced in the original PR; the new error would live next to it).
  • src/infra/outbound/channel-selection.tsresolveMessageChannelSelection. The webchat check is at the top of the explicit-channel branch in the original PR.
  • src/cron/jobs.tsresolveDeliveryTarget, where the wrapping happens today.
  • Documented contract: docs/automation/cron-jobs.md — the "Webchat is not an announce target" subsection added by the original PR.

The original PR link will be added in a comment here once it is opened.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low-priority cleanup, docs, polish, ergonomics, or speculative work.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions