Problem
RetryPolicy validates constructor parameters using comparison operators (<=, <) that silently accept NaN and Infinity because JavaScript NaN comparisons always return false.
File: packages/durabletask-js/src/task/retry/retry-policy.ts, lines 67-94
For example:
// NaN <= 0 evaluates to false, so NaN passes this validation!
if (maxNumberOfAttempts <= 0) {
throw new Error("maxNumberOfAttempts must be greater than zero");
}
Root Cause
JavaScript NaN comparison semantics: NaN <= 0, NaN < 1.0, and NaN >= x all return false. This means every comparison-based guard in the constructor is bypassed when NaN is passed.
This can happen when users compute retry parameters from external sources:
const maxAttempts = parseInt(process.env.MAX_RETRIES!); // NaN if env var is undefined
Impact
maxNumberOfAttempts: NaN — Most severe. The check attemptCount >= maxNumberOfAttempts in RetryableTask.computeNextDelayInMilliseconds() always returns false when maxNumberOfAttempts is NaN, causing infinite retries that never stop.
firstRetryIntervalInMilliseconds: NaN — Produces NaN timer delays, creating timers with Invalid Date.
backoffCoefficient: NaN — Produces NaN delay values on all retry calculations.
Infinity values — Similar issues: Infinity maxNumberOfAttempts allows unlimited retries, Infinity intervals create timers that cannot fire.
Proposed Fix
Add Number.isFinite() guards before all comparison checks in the RetryPolicy constructor. Number.isFinite() returns false for NaN, Infinity, and -Infinity, catching all invalid numeric values.
Problem
RetryPolicyvalidates constructor parameters using comparison operators (<=,<) that silently acceptNaNandInfinitybecause JavaScript NaN comparisons always returnfalse.File:
packages/durabletask-js/src/task/retry/retry-policy.ts, lines 67-94For example:
Root Cause
JavaScript NaN comparison semantics:
NaN <= 0,NaN < 1.0, andNaN >= xall returnfalse. This means every comparison-based guard in the constructor is bypassed when NaN is passed.This can happen when users compute retry parameters from external sources:
Impact
maxNumberOfAttempts: NaN— Most severe. The checkattemptCount >= maxNumberOfAttemptsinRetryableTask.computeNextDelayInMilliseconds()always returnsfalsewhenmaxNumberOfAttemptsisNaN, causing infinite retries that never stop.firstRetryIntervalInMilliseconds: NaN— ProducesNaNtimer delays, creating timers withInvalid Date.backoffCoefficient: NaN— ProducesNaNdelay values on all retry calculations.Infinityvalues — Similar issues:InfinitymaxNumberOfAttempts allows unlimited retries,Infinityintervals create timers that cannot fire.Proposed Fix
Add
Number.isFinite()guards before all comparison checks in theRetryPolicyconstructor.Number.isFinite()returnsfalseforNaN,Infinity, and-Infinity, catching all invalid numeric values.