openclaw - ✅(Solved) Fix parseDurationMs rejects zero and negative values but allows arbitrarily large floats [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#83906Fetched 2026-05-20 03:47:02
View on GitHub
Comments
1
Participants
2
Timeline
12
Reactions
1
Timeline (top)
labeled ×7unlabeled ×2commented ×1cross-referenced ×1

Fix Action

Fix / Workaround

Severity: low / Confidence: medium / Category: bug Triage: risk Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-1de66cf308-_05e16acd04.

PR fix notes

PR #84047: fix(cli): reject duration overflow in parseDurationMs (#83906)

Description (problem / solution / changelog)

Fixes #83906.

parseDurationMs (src/cli/cron-cli/shared.ts:100-125) correctly rejected non-positive values, but accepted any positive float that parses finitely — including digit-strings that overflow only after the unit factor multiplication. The regex /^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i strips e notation, so the realistic overflow path is a long pure-digit number: 1 followed by 302 zeros + d produces n = 1e302 (finite double), but n * 86_400_000 is Infinity. Math.floor(Infinity) is still Infinity, which slipped through every null / positive-number check at callers and landed as everyMs: Infinity (or cooldown: Infinity) in cron schedule payloads sent to the gateway.

The reporter's example 1e308d is intercepted earlier by the digits-only regex; the real-world overflow path is the long-digit case the new check catches.

Changes

  • src/cli/cron-cli/shared.ts: hoist Math.floor(n * factor) to a local result const and return null if !Number.isFinite(result). The existing !Number.isFinite(n) || n <= 0 guard already covers the parseFloat-Infinity input path (e.g. 310 consecutive digits); the new guard catches the in-between window where n is finite but the product is not.
  • src/cli/cron-cli/shared.test.ts: import parseDurationMs and add a focused describe block with 4 regression cases — ordinary durations in each unit (no regression), zero/malformed (no regression), the overflow-on-factor-multiplication case (the new guard), and the parseFloat-Infinity input (already-rejected; pinned so a future refactor can't regress either failure mode).

Diff stat: 2 files, +47 / -1.

Real behavior proof

  • Behavior or issue addressed: Sanitized issue evidence — parseDurationMs returned Math.floor(Infinity) === Infinity for inputs whose pure-digit float overflowed only after the unit-factor multiplication. The reporter's literal 1e308d example is filtered earlier by the regex, but the same code path is reachable with long digit strings (e.g. 1 + 302 zeros + d).

  • Real environment tested: Local Node 22.x. Probe at /tmp/probe_83906.mjs (a) parses the patched shared.ts and verifies the result hoist, the !Number.isFinite(result) check, and the new return result shape; and (b) replays both the patched and pre-fix shapes against 8 fixtures: ordinary 500ms / 1.5h / 3d, zero, malformed, unit-only, the realistic overflow path (1 + 302 zeros + d → patched returns null, buggy returns Infinity), and the parseFloat-Infinity input (9 × 310 + d → both reject because n itself is Infinity).

  • Exact steps or command run after this patch: node /tmp/probe_83906.mjs

  • Evidence after fix:

PASS: result hoisted to a local const
PASS: finite-check rejects Infinity after factor multiplication
PASS: function returns the finite value via the new const
PASS: replay: all 8 fixtures (ordinary / zero / malformed / overflow / pre-overflow / already-Infinity) match patched and buggy shapes
PASS: issue repro (realistic overflow path): buggy=Infinity (would leak as everyMs), patched=null (clean rejection)

ALL CASES PASS
  • Observed result after fix: Inputs whose pure-digit float overflows only after unit-factor multiplication now return null cleanly, matching the existing behavior for zero, negative, and malformed input. Callers' existing null-checks reject the overflow case before it reaches the gateway as everyMs: Infinity.

  • What was not tested: Live openclaw cron add --every <bigdigits>d ... smoke against an actual build — that requires pnpm build. The vitest regression cases exercise the public parseDurationMs contract directly, and the probe replays both the patched and buggy shapes against the same overflow fixture.

Audit (per CLAUDE rules — all 5 steps)

  • Existing-helper check: Reuses the existing Number.isFinite predicate and the existing Math.floor flow. No new helper. PASS
  • Shared-helper caller check: parseDurationMs (cron-cli/shared.ts version) has 3 production callers: schedule-options.ts:112 (everyMs), register.cron-edit.ts:358 (failure-alert cooldown), and the same-file parseAt:180 (--at relative offset). All three already handle null by treating the input as invalid; the additional guard only converts Infinity outputs to null, strengthening — not changing — the contract. PASS
  • Broader-fix rival scan: gh pr list --search '83906 in:title,body' and gh pr list --search 'parseDurationMs in:title,body' return no open PRs. PASS
  • Recent-merge audit: git log --oneline -5 -- src/cli/cron-cli/shared.ts shows e1061a8b46 test(live): tolerate provider drift in release checks — unrelated. PASS
  • Prototype-pollution scan: N/A — single numeric comparison.

Changed files

  • src/cli/cron-cli/shared.test.ts (modified, +36/-0)
  • src/cli/cron-cli/shared.ts (modified, +11/-1)

Code Example

const n = Number.parseFloat(match[1] ?? "");
  if (!Number.isFinite(n) || n <= 0) {
    return null;
  }
RAW_BUFFERClick to expand / collapse

Severity: low / Confidence: medium / Category: bug Triage: risk Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol

Evidence

  • src/cli/cron-cli/shared.ts:163-182 (parseDurationMs)
const n = Number.parseFloat(match[1] ?? "");
  if (!Number.isFinite(n) || n <= 0) {
    return null;
  }

Reasoning

parseDurationMs correctly rejects non-positive values but accepts any positive float, including values that overflow when multiplied by the unit factor (e.g. 1e308 * 86_400_000 = Infinity). Math.floor(Infinity) returns Infinity, so callers receive Infinity as a valid duration. Downstream comparison like durationMs < 0 will not catch this. Also called from parseCronRunWaitDuration which checks isFinite after the call, so the wait-timeout path would reject Infinity; but parseDurationMs callers in schedule-options.ts (everyMs) do not add that extra check.

Reproduction

Run openclaw cron add --name x --every 1e308d --message hi --agent a. everyMs will be Infinity, passed to the gateway.

Recommendation

Add an Number.isFinite(result) check before returning from parseDurationMs (after Math.floor), returning null if not finite.

Why existing tests miss this

No unit tests for parseDurationMs edge cases.

Suggested regression test

Test that parseDurationMs('1e308d') returns null.

Minimum fix scope

Add if (!Number.isFinite(result)) return null; before the return in parseDurationMs.


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-1de66cf308-_05e16acd04.

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 parseDurationMs rejects zero and negative values but allows arbitrarily large floats [1 pull requests, 1 comments, 2 participants]