openclaw - ✅(Solved) Fix Cron runs with delivery.mode=none still emit misleading delivery.resolved.error in run record [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72210Fetched 2026-04-27 05:33:12
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Timeline (top)
cross-referenced ×2commented ×1

When an openclaw cron job has delivery.mode: "none" (set via openclaw cron edit --no-deliver), individual run records in ~/.openclaw/cron/runs/<job-id>.jsonl still contain a delivery.resolved object with an ok: false and an error field — even though the runtime correctly sets deliveryStatus: "not-requested" and doesn't actually attempt delivery.

This is misleading. Anyone (or any LLM agent) inspecting the run record sees delivered: false plus an error like "Channel is required when multiple channels are configured: discord, telegram" and reasonably assumes the cron is broken — when in fact delivery was intentionally disabled.

Error Message

When an openclaw cron job has delivery.mode: "none" (set via openclaw cron edit --no-deliver), individual run records in ~/.openclaw/cron/runs/<job-id>.jsonl still contain a delivery.resolved object with an ok: false and an error field — even though the runtime correctly sets deliveryStatus: "not-requested" and doesn't actually attempt delivery. This is misleading. Anyone (or any LLM agent) inspecting the run record sees delivered: false plus an error like "Channel is required when multiple channels are configured: discord, telegram" and reasonably assumes the cron is broken — when in fact delivery was intentionally disabled. "error": "Channel is required when multiple channels are configured: discord, telegram. Set delivery.channel explicitly or use a main session with a previous channel." deliveryStatus: "not-requested" and the jobs.json having "delivery": {"mode": "none"} both correctly signal that the wrapper isn't supposed to deliver. But the resolved-error noise drowns that signal at first glance. deliveryStatus: "not-requested" already carries the correct signal; the resolved.error contradicts it.

Root Cause

Cosmetic on the surface, but real diagnostic-noise impact:

  • Operators reading run records mistakenly conclude their cron is failing
  • LLM agents inspecting their own state (which is increasingly common with agent-tools-MCP bridges) trip on the false-negative and try to "troubleshoot" working code
  • Net effect: time burned chasing a non-issue

Fix Action

Fixed

PR fix notes

PR #72219: fix(cron): omit misleading resolved error in run record when delivery.mode is none

Description (problem / solution / changelog)

Summary

  • Problem: When a cron job has delivery.mode: "none" (set via openclaw cron edit --no-deliver), the run record still contains a delivery.resolved object with ok: false and an error message like "delivery is disabled". This is misleading because delivery was intentionally disabled, not failing.
  • Why it matters: Operators and LLM agents inspecting run records mistakenly conclude the cron is broken when it is working as intended.
  • What changed: In buildCronDeliveryTrace, when deliveryPlan.mode === "none", the resolved field is now omitted from the delivery trace instead of being populated with a faux-failure error.
  • What did NOT change: Behavior for announce and webhook delivery modes is unchanged. The deliveryStatus: "not-requested" signal remains intact.

Change Type

  • Bug fix

Scope

  • Gateway / orchestration

Linked Issue/PR

  • Closes #72210

Root Cause

  • Root cause: resolveCronDeliveryContext creates a resolvedDelivery with ok: false and error: new Error("delivery is disabled") when mode === "none". buildCronDeliveryTrace then unconditionally serializes this error into the run record, creating a false-negative signal that contradicts the correct deliveryStatus: "not-requested".
  • Missing detection / guardrail: No gate existed to skip or neutralize the resolved block when delivery was explicitly disabled.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/cron/isolated-agent/run.message-tool-policy.test.ts
  • Scenario the test should lock in: A cron run with delivery.mode: "none" must not produce a delivery.resolved field in the result.
  • Existing test that already covers this: None; added a new test case.

User-visible / Behavior Changes

  • Cron run records for delivery.mode=none jobs no longer contain a misleading delivery.resolved.error field.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux
  • Runtime: Node 22

Steps

  1. Configure a cron job with delivery.mode: "none".
  2. Trigger a manual run.
  3. Inspect the run record in ~/.openclaw/cron/runs/<job-id>.jsonl.

Expected

  • The run record does not contain a delivery.resolved block (or contains neutral metadata).

Actual (before fix)

  • The run record contains delivery.resolved.ok: false with error: "delivery is disabled".

Evidence

  • Failing test/log before + passing after: Added omits resolved delivery trace when delivery.mode is none test; passes after the fix.

Human Verification

  • Verified scenarios: Local unit tests (pnpm test src/cron/isolated-agent/run.message-tool-policy.test.ts) pass (28/28). Lint (pnpm lint) and typecheck (pnpm tsgo) pass.
  • Edge cases checked: announce and webhook modes still produce resolved traces as before.
  • What I did not verify: Full integration test with a live gateway instance.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Downstream consumers might expect delivery.resolved to always exist.
    • Mitigation: The CronDeliveryTrace type already marks resolved as optional (resolved?: ...), so consumers should already handle its absence. Existing tests confirm no breakage.

Changed files

  • src/cron/isolated-agent/run.message-tool-policy.test.ts (modified, +13/-0)
  • src/cron/isolated-agent/run.ts (modified, +26/-23)

Code Example

{
  "status": "ok",
  "deliveryStatus": "not-requested",
  "delivered": false,
  "delivery": {
    "intended": { "channel": "last", "to": null, "source": "last" },
    "resolved": {
      "ok": false,
      "to": null,
      "source": "last",
      "error": "Channel is required when multiple channels are configured: discord, telegram. Set delivery.channel explicitly or use a main session with a previous channel."
    },
    "messageToolSentTo": [{"channel": "telegram", "to": "telegram:-...."}],
    "fallbackUsed": false,
    "delivered": false
  }
}
RAW_BUFFERClick to expand / collapse

Summary

When an openclaw cron job has delivery.mode: "none" (set via openclaw cron edit --no-deliver), individual run records in ~/.openclaw/cron/runs/<job-id>.jsonl still contain a delivery.resolved object with an ok: false and an error field — even though the runtime correctly sets deliveryStatus: "not-requested" and doesn't actually attempt delivery.

This is misleading. Anyone (or any LLM agent) inspecting the run record sees delivered: false plus an error like "Channel is required when multiple channels are configured: discord, telegram" and reasonably assumes the cron is broken — when in fact delivery was intentionally disabled.

Reproduction

  1. Have an openclaw 2026.4.24 gateway with multiple channels configured (e.g. telegram + discord both enabled).
  2. Take any agent-turn cron job and run openclaw cron edit <id> --no-deliver.
  3. Trigger a manual run with openclaw cron run <id>.
  4. Inspect the resulting line in ~/.openclaw/cron/runs/<id>.jsonl.

Observed (with mode: none set):

{
  "status": "ok",
  "deliveryStatus": "not-requested",
  "delivered": false,
  "delivery": {
    "intended": { "channel": "last", "to": null, "source": "last" },
    "resolved": {
      "ok": false,
      "to": null,
      "source": "last",
      "error": "Channel is required when multiple channels are configured: discord, telegram. Set delivery.channel explicitly or use a main session with a previous channel."
    },
    "messageToolSentTo": [{"channel": "telegram", "to": "telegram:-...."}],
    "fallbackUsed": false,
    "delivered": false
  }
}

deliveryStatus: "not-requested" and the jobs.json having "delivery": {"mode": "none"} both correctly signal that the wrapper isn't supposed to deliver. But the resolved-error noise drowns that signal at first glance.

Expected

When delivery.mode == "none":

  • Either omit the delivery.resolved block entirely from the run record,
  • or populate it with neutral metadata (e.g. {"ok": true, "skipped": true, "reason": "delivery.mode=none"}) so it doesn't read as a failure.

deliveryStatus: "not-requested" already carries the correct signal; the resolved.error contradicts it.

Why this matters

Cosmetic on the surface, but real diagnostic-noise impact:

  • Operators reading run records mistakenly conclude their cron is failing
  • LLM agents inspecting their own state (which is increasingly common with agent-tools-MCP bridges) trip on the false-negative and try to "troubleshoot" working code
  • Net effect: time burned chasing a non-issue

Environment

  • openclaw 2026.4.24
  • macOS (Apple Silicon)
  • Telegram + Discord channels both enabled at gateway level
  • Cron job is agentTurn payload with --no-deliver, agent posts to Telegram via the message tool directly

Suggested fix scope

Trivial — gate the resolved population on mode != "none" in whichever cron-runner module assembles the run record. Should be a few lines of guard logic in the runtime wrapper.

extent analysis

TL;DR

Modify the cron-runner module to conditionally omit or neutralize the delivery.resolved block when delivery.mode is set to "none".

Guidance

  • Identify the cron-runner module responsible for assembling the run record and locate the logic that populates the delivery.resolved block.
  • Add a conditional statement to check if delivery.mode is "none" before populating the delivery.resolved block.
  • Either omit the delivery.resolved block entirely or populate it with neutral metadata (e.g., {"ok": true, "skipped": true, "reason": "delivery.mode=none"}) when delivery.mode is "none".
  • Verify that the modified cron-runner module correctly handles the delivery.mode condition and updates the run record accordingly.

Example

if (delivery.mode !== "none") {
  // populate delivery.resolved block
} else {
  // omit or populate with neutral metadata
  delivery.resolved = { "ok": true, "skipped": true, "reason": "delivery.mode=none" };
}

Notes

The suggested fix assumes that the cron-runner module has access to the delivery.mode value and can conditionally modify the delivery.resolved block. The exact implementation may vary depending on the module's internal logic and architecture.

Recommendation

Apply the suggested workaround by modifying the cron-runner module to conditionally omit or neutralize the delivery.resolved block when delivery.mode is set to "none", as this will correctly signal that delivery was intentionally disabled and prevent diagnostic noise.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Cron runs with delivery.mode=none still emit misleading delivery.resolved.error in run record [1 pull requests, 1 comments, 2 participants]