openclaw - ✅(Solved) Fix [Bug]: `cron edit` persists invalid `--cron` expressions on disabled jobs and can leave them enabled after failed enable [5 pull requests, 2 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#74459Fetched 2026-04-30 06:23:46
View on GitHub
Comments
2
Participants
2
Timeline
12
Reactions
2
Author
Timeline (top)
cross-referenced ×5commented ×2labeled ×2referenced ×2

openclaw cron edit <id> --cron <invalid> rejects invalid cron expressions for enabled jobs, but accepts and persists the same invalid expression when the target job is disabled; a later openclaw cron enable <id> returns an error while leaving the invalid job enabled in live state.

Error Message

GatewayClientRequestError: invalid cron.update params: CronPattern: Invalid value for month: 12

Root Cause

Root cause appears to be that src/cron/service/ops.ts applies the patch in-place before schedule computation, while src/gateway/server-methods/cron.ts does not validate cron expressions before calling context.cron.update. Invalid schedules can therefore mutate live state before the error response is returned.

Fix Action

Fix / Workaround

Root cause appears to be that src/cron/service/ops.ts applies the patch in-place before schedule computation, while src/gateway/server-methods/cron.ts does not validate cron expressions before calling context.cron.update. Invalid schedules can therefore mutate live state before the error response is returned.

PR fix notes

PR #74068: fix(cron): reject invalid schedule edits before mutation

Description (problem / solution / changelog)

Summary

  • Problem: cron edit <id> --cron <invalid> could persist an invalid cron expression when the target job was disabled, and a later failed cron enable could leave the invalid job enabled in live state.
  • Why it matters: rejected cron input should never mutate in-memory or persisted scheduler state; this creates confusing CLI output and schedule-error state after an operation that returned an error.
  • What changed: validate cron schedules in the gateway handler before calling cron.add / cron.update, so invalid Croner expressions are rejected before the cron service applies any patch.
  • What did NOT change (scope boundary): no changes to cron execution, retry/backoff policy, persistence format, delivery behavior, or existing cleanup/repair paths.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #74459
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: cron.update applies patches in-place before computing the next run. The gateway handler validated only timestamp shape before calling context.cron.update(...), so disabled jobs could bypass schedule computation and persist invalid cron expressions.
  • Missing detection / guardrail: gateway validation did not validate cron expressions before service mutation.
  • Contributing context (if known): disabled jobs do not compute a next run during edit, so the invalid cron expression was not rejected on that path.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server-methods/cron.validation.test.ts
  • Scenario the test should lock in: invalid cron schedules are rejected before context.cron.add / context.cron.update, including disabled-job updates.
  • Why this is the smallest reliable guardrail: the bug is at the gateway boundary before the cron service mutation call.
  • Existing test that already covers this (if any): none for the disabled-job pre-mutation path.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

cron edit <id> --cron <invalid> now fails before mutating disabled jobs, matching the expected behavior for invalid cron input.

Diagram (if applicable)

Before:
cron edit disabled job --cron invalid -> patch applied -> exit 0 -> invalid schedule persisted
cron enable same job -> error returned -> live state may still show enabled invalid job

After:
cron edit disabled job --cron invalid -> gateway validation rejects -> previous schedule remains unchanged

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Ubuntu 24.04.4 LTS
  • Runtime/container: Node 22.22.1 / pnpm dev
  • Model/provider: N/A
  • Integration/channel (if any): Cron gateway RPC
  • Relevant config (redacted): isolated OPENCLAW_STATE_DIR source gateway on loopback

Steps

  1. Create a disabled valid cron job with cron add --every 10m --session main --system-event "probe" --disabled.
  2. Run cron edit <job-id> --cron "* * * 13 *".
  3. Inspect cron show <job-id> --json and jobs.json.

Expected

  • Invalid cron expression is rejected.
  • Previous valid schedule remains in live state and persisted jobs.json.

Actual

  • Before this PR: invalid cron schedule could be persisted on disabled jobs.
  • After this PR: invalid cron edit returns INVALID_REQUEST, and the previous valid every schedule remains unchanged.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Targeted test:

pnpm test src/gateway/server-methods/cron.validation.test.ts -- --reporter=verbose
# 10 tests passed

Build:

pnpm build
# passed

Changed gate note:

pnpm check:changed -- --base openclaw/main
# touched production typecheck passed; current main has an unrelated core test type error in src/gateway/channel-health-policy.test.ts:235

Human Verification (required)

What I personally verified (not just CI), and how:

  • Verified scenarios: isolated source gateway smoke reproduced the disabled-job invalid cron edit; after the fix, cron edit <id> --cron "* * * 13 *" returns exit 1 and both cron show and jobs.json keep the original valid every schedule.
  • Edge cases checked: invalid cron.add schedule rejection before service mutation; invalid cron.update schedule rejection before service mutation; disabled-job update path.
  • What I did not verify: long-running cron execution timing, delivery channels, or production systemd gateway behavior.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Cron validation now happens before service mutation, so any cron expression Croner rejects will be rejected earlier than before.
    • Mitigation: this matches the intended invalid-input behavior and is covered by gateway boundary tests.

Changed files

  • src/gateway/server-methods/cron.ts (modified, +33/-0)
  • src/gateway/server-methods/cron.validation.test.ts (modified, +44/-0)

PR #74654: fix(cron): validate cron expression before mutating stored job on update (#74459)

Description (problem / solution / changelog)

Summary

Fixes #74459.

cron edit <id> --cron <invalid> on a disabled job silently persisted the invalid expression — the scheduler's next-run computation was skipped for disabled jobs, so the invalid cron string passed through applyJobPatch without error. A subsequent cron enable would then set enabled = true before Croner threw, leaving the job stuck in an enabled-but-unscheduled state.

Fix

Two-layer guard before any mutation in cron.update:

  1. Schedule validation helpervalidateCronScheduleExpr exported from src/cron/schedule.ts. Calls Croner with the expression; throws RangeError on invalid input.
  2. Pre-mutation call in ops.ts — validates before applyJobPatch when:
    • the patch supplies a new cron expression, OR
    • the patch enables a job whose existing schedule is cron-kind (catches the double-failure path)

Both paths throw before any field is mutated, so on-disk job state is never corrupted.

Tests

  • src/cron/service.issue-regressions.test.ts: 2 new regression tests at service level
    • disabled job: invalid --cron rejected before persist
    • disabled job: valid --cron accepted; subsequent cron enable with a corrupted schedule throws
  • src/gateway/server-methods/cron.validation.test.ts: 1 gateway-level regression test
Tests  20 passed (20) across 2 shards

Audit

  • Audit A (existing helper): validateCronExpression not present; validateCronScheduleExpr is a new focused helper in schedule.ts (consistent with the module's existing CronSchedule type)
  • Audit B (shared callers): ops.ts#updateCronJob — 1 caller path. New guard is additive (throws before mutation), no contract change for valid inputs
  • Audit C (broader rival): PR #74068 addresses gateway-layer validation only (2 files). This fix adds service-layer validation + a shared validateCronScheduleExpr helper (5 files, wider coverage). Complementary rather than competing — both layers benefit.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/cron/schedule.ts (modified, +4/-0)
  • src/cron/service.issue-regressions.test.ts (modified, +67/-0)
  • src/cron/service/ops.ts (modified, +9/-0)
  • src/gateway/server-methods/cron.validation.test.ts (modified, +31/-0)

PR #74720: fix: reject invalid cron edits on disabled jobs

Description (problem / solution / changelog)

Summary

  • validate cron schedule edits before persisting them, even when the target job is disabled
  • make cron.update transactional so failed enable/update attempts do not partially mutate stored jobs
  • add regression coverage for both invalid disabled edits and failed enables against already-invalid disabled jobs

Testing

  • pnpm vitest run src/cron/service.issue-regressions.test.ts src/gateway/server-methods/cron.validation.test.ts

Closes #74459.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/cron/service.issue-regressions.test.ts (modified, +55/-0)
  • src/cron/service/ops.ts (modified, +29/-17)

PR #13: fix(cron): reject invalid cron expressions on disabled jobs before persisting

Description (problem / solution / changelog)

Closes openclaw/openclaw#74459

Problem

openclaw cron edit <id> --cron "invalid expr" on a disabled job silently persisted the invalid expression. Two bugs:

  1. ops.update only calls computeJobNextRunAtMs (which validates via croner) for enabled jobs. Disabled jobs skip that path entirely, so invalid cron syntax passes through to persist().
  2. When the user later ran cron edit --enable, applyJobPatch set job.enabled = true before computeJobNextRunAtMs threw, leaving the in-memory state.store.jobs entry with enabled: true even though persist was never reached. This "live state" corruption persisted until the next forced reload from disk.

Root cause

src/cron/service/ops.ts:update:

applyJobPatch(job, patch, ...); // mutates job.enabled = true in-place
// ...
if (job.enabled) {
  job.state.nextRunAtMs = computeJobNextRunAtMs(job, now); // only here does croner throw
}
// For disabled jobs: skips computeJobNextRunAtMs entirely → persist runs with invalid expr

Fix

Added validateCronScheduleExpr(schedule) to src/cron/validate-timestamp.ts. It dry-runs computeNextRunAtMs in a try/catch to detect croner parse errors for any cron-kind schedule.

Three call sites:

  • gateway/server-methods/cron.tscron.add and cron.update handlers: validate before reaching context.cron.* (returns structured error to caller)
  • src/cron/service/ops.tsupdate: validate before applyJobPatch so the job object is never mutated when the expression is invalid (defense in depth)

Tests

New file src/cron/service.cron-invalid-expr.test.ts (3 tests):

  • Rejects invalid cron expression on a disabled job; original schedule unchanged
  • Rejects invalid expression when trying to enable with the bad schedule
  • Accepts a valid cron expression change on a disabled job

Generated by Claude Code

<!-- devin-review-badge-begin -->
<a href="https://app.devin.ai/review/suboss87/openclaw/pull/13" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end -->

Changed files

  • src/cron/service.cron-invalid-expr.test.ts (added, +133/-0)
  • src/cron/service/ops.ts (modified, +9/-0)
  • src/cron/validate-timestamp.ts (modified, +23/-0)
  • src/gateway/server-methods/cron.ts (modified, +18/-1)

PR #74812: fix(cron): validate cron expression before persisting to job state

Description (problem / solution / changelog)

Summary

Fixes #74459: Prevents invalid cron expressions from being persisted in disabled jobs that would fail silently when enabled later.

Problem

When a cron job is disabled, users can save invalid cron expressions (e.g., * * * 13 * - month 13 doesn not exist). The expression is stored without validation. When the job is enabled later, it fails at runtime with no clear error message.

Solution

Add upfront cron expression validation using the croner library (same library used for computing next run times) in gateway handlers:

  1. cron.add: Validate cron expressions before creating the job
  2. cron.update: Validate cron expressions before applying the patch

This ensures invalid expressions are rejected with clear error messages BEFORE they are saved to job state, not at runtime.

Implementation

  • Create validateCronExpression() in src/cron/validate-cron-expression.ts
  • Validate in both cron.add and cron.update gateway handlers
  • Add comprehensive test coverage for valid/invalid expressions

Testing

Added tests in:

  • src/cron/validate-cron-expression.test.ts - unit tests for validation function
  • src/gateway/server-methods/cron.validation.test.ts - integration tests for gateway handlers

Test cases include:

  • Valid expressions: * * * * *, 0 0 * * *, with timezone
  • Invalid expressions: month 13, day of week 8, hour 25, empty/undefined
  • Edge cases: whitespace, predefined aliases (@daily, @hourly)

Checklist

  • Issue linked in title and body
  • Semantic commit message format
  • Test coverage added
  • No CHANGELOG update (maintainers handle this)

Changed files

  • src/cron/validate-cron-expression.test.ts (added, +98/-0)
  • src/cron/validate-cron-expression.ts (added, +61/-0)
  • src/gateway/server-methods/cron.ts (modified, +32/-0)
  • src/gateway/server-methods/cron.validation.test.ts (modified, +92/-0)

Code Example

openclaw cron add --name probe --every 10m --session main --system-event "probe" --disabled

---

openclaw cron edit <job-id> --cron "* * * 13 *"

---

openclaw cron show <job-id> --json

---

openclaw cron enable <job-id>

---

openclaw cron show <job-id> --json

---

"schedule": { "kind": "cron", "expr": "* * * 13 *" },
"enabled": false

---

GatewayClientRequestError: invalid cron.update params: CronPattern: Invalid value for month: 12

---

$ openclaw cron add --name probe --every 10m --session main --system-event "probe" --disabled
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "enabled": false,
  "schedule": { "kind": "every", "everyMs": 600000, "anchorMs": 1777475041128 }
}

$ openclaw cron edit 70f4b9b8-d501-4315-98cf-f645b49b6386 --cron "* * * 13 *"
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "enabled": false,
  "schedule": { "kind": "cron", "expr": "* * * 13 *" }
}

$ openclaw cron enable 70f4b9b8-d501-4315-98cf-f645b49b6386
GatewayClientRequestError: invalid cron.update params: CronPattern: Invalid value for month: 12

$ openclaw cron show 70f4b9b8-d501-4315-98cf-f645b49b6386 --json
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "schedule": { "kind": "cron", "expr": "* * * 13 *" },
  "enabled": true,
  "state": {
    "scheduleErrorCount": 1,
    "lastError": "schedule error: RangeError: CronPattern: Invalid value for month: 12"
  }
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

openclaw cron edit <id> --cron <invalid> rejects invalid cron expressions for enabled jobs, but accepts and persists the same invalid expression when the target job is disabled; a later openclaw cron enable <id> returns an error while leaving the invalid job enabled in live state.

Steps to reproduce

  1. Start OpenClaw from current main (204ef7f1c4) with a reachable gateway.
  2. Create a disabled valid cron job:
    openclaw cron add --name probe --every 10m --session main --system-event "probe" --disabled
  3. Edit it to an invalid cron expression:
    openclaw cron edit <job-id> --cron "* * * 13 *"
  4. Run:
    openclaw cron show <job-id> --json
  5. Run:
    openclaw cron enable <job-id>
  6. Run:
    openclaw cron show <job-id> --json

Expected behavior

Invalid --cron expressions should be rejected before mutating cron state, regardless of whether the target job is enabled or disabled. The job should keep its previous valid schedule.

Actual behavior

cron edit exits 0 for a disabled job and persists:

"schedule": { "kind": "cron", "expr": "* * * 13 *" },
"enabled": false

Then cron enable exits 1 with:

GatewayClientRequestError: invalid cron.update params: CronPattern: Invalid value for month: 12

But cron show reports the job as enabled with the invalid schedule and schedule-error state.

OpenClaw version

2026.4.27 (204ef7f)

Operating system

Ubuntu 24.04.4 LTS

Install method

pnpm dev

Model

N/A

Provider / routing chain

N/A

Additional provider/model setup details

No response

Logs, screenshots, and evidence

$ openclaw cron add --name probe --every 10m --session main --system-event "probe" --disabled
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "enabled": false,
  "schedule": { "kind": "every", "everyMs": 600000, "anchorMs": 1777475041128 }
}

$ openclaw cron edit 70f4b9b8-d501-4315-98cf-f645b49b6386 --cron "* * * 13 *"
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "enabled": false,
  "schedule": { "kind": "cron", "expr": "* * * 13 *" }
}

$ openclaw cron enable 70f4b9b8-d501-4315-98cf-f645b49b6386
GatewayClientRequestError: invalid cron.update params: CronPattern: Invalid value for month: 12

$ openclaw cron show 70f4b9b8-d501-4315-98cf-f645b49b6386 --json
{
  "id": "70f4b9b8-d501-4315-98cf-f645b49b6386",
  "schedule": { "kind": "cron", "expr": "* * * 13 *" },
  "enabled": true,
  "state": {
    "scheduleErrorCount": 1,
    "lastError": "schedule error: RangeError: CronPattern: Invalid value for month: 12"
  }
}

Impact and severity

Affected users/systems/channels: users editing disabled cron jobs with --cron.

Severity: reliability / state consistency bug. A rejected invalid schedule should not be accepted into cron state.

Frequency: deterministic for disabled jobs edited to an invalid cron expression.

Consequence: cron state can contain an invalid enabled job after a failed enable path, creating confusing CLI behavior and schedule-error state that should have been rejected upfront.

Additional information

Root cause appears to be that src/cron/service/ops.ts applies the patch in-place before schedule computation, while src/gateway/server-methods/cron.ts does not validate cron expressions before calling context.cron.update. Invalid schedules can therefore mutate live state before the error response is returned.

extent analysis

TL;DR

Validate cron expressions before applying patches to cron state to prevent invalid schedules from being persisted.

Guidance

  • Validate cron expressions in src/cron/service/ops.ts before applying patches to ensure invalid schedules are rejected upfront.
  • Consider adding input validation for cron expressions in src/gateway/server-methods/cron.ts to prevent invalid data from being sent to context.cron.update.
  • Review the error handling in openclaw cron enable to ensure that it correctly handles and reports errors when enabling a job with an invalid schedule.
  • Verify that the cron show command accurately reflects the state of the job after an enable or edit operation.

Example

// src/cron/service/ops.ts
function validateCronExpression(expr: string): boolean {
  // implementation of cron expression validation
}

function editCronJob(id: string, cronExpr: string) {
  if (!validateCronExpression(cronExpr)) {
    throw new Error('Invalid cron expression');
  }
  // apply patch to cron state
}

Notes

The provided information suggests that the issue is due to the lack of validation for cron expressions before applying patches to cron state. However, without the full implementation details, it's difficult to provide a complete solution.

Recommendation

Apply workaround by adding input validation for cron expressions in src/cron/service/ops.ts to prevent invalid schedules from being persisted. This will ensure that invalid cron expressions are rejected before mutating cron state.

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…

FAQ

Expected behavior

Invalid --cron expressions should be rejected before mutating cron state, regardless of whether the target job is enabled or disabled. The job should keep its previous valid schedule.

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 [Bug]: `cron edit` persists invalid `--cron` expressions on disabled jobs and can leave them enabled after failed enable [5 pull requests, 2 comments, 2 participants]