HangfireIO/Hangfire · error · ArgumentException

DelaysInSeconds value must be an array of non-negative numbe

Error message

DelaysInSeconds value must be an array of non-negative numbers.

What it means

The DelaysInSeconds property on AutomaticRetryAttribute lets you specify an explicit per-attempt delay array instead of the default exponential backoff. Each element must be a non-negative integer; a null value is allowed (reverts to default), but an empty array or any negative element throws ArgumentException. This is assignment-time validation on the configuration property.

Source

Thrown at src/Hangfire.Core/AutomaticRetryAttribute.cs:157

        }

        /// <summary>
        /// Gets or sets the delays between attempts.
        /// </summary>
        /// <value>An array of non-negative numbers.</value>
        /// <exception cref="ArgumentNullException">The value in a set operation is null.</exception>
        /// <exception cref="ArgumentException">The value contain one or more negative numbers.</exception>
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public int[] DelaysInSeconds
        {
            get { lock (_lockObject) { return _delaysInSeconds; } }
            set
            {
                if (value != null)
                {
                    if (value.Length == 0) throw new ArgumentNullException(nameof(value));
                    if (value.Any(static delay => delay < 0))
                        throw new ArgumentException(
                            $@"{nameof(DelaysInSeconds)} value must be an array of non-negative numbers.",
                            nameof(value));
                }

                lock (_lockObject) { _delaysInSeconds = value; }
            }
        }

        /// <summary>
        /// Gets or sets a function using to get a delay by an attempt number.
        /// </summary>
        /// <exception cref="ArgumentNullException">The value in a set operation is null.</exception>
        [JsonIgnore]
        public Func<long, int> DelayInSecondsByAttemptFunc
        {
            get { lock (_lockObject) { return _delayInSecondsByAttemptFunc;} }
            set
            {

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Replace negative values with 0 (zero-second delay) for immediate retries, or use positive seconds for real delays.
  2. Ensure the array is non-empty when non-null — provide at least as many entries as Attempts, or use the default backoff by leaving DelaysInSeconds null.
  3. Sanitize config arrays before assignment: filter out negatives and guard against empty.

Example fix

// before
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[]{-1, 5, 10})]

// after
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[]{0, 5, 10})]
Defensive patterns

Strategy: validation

Validate before calling

int[] delays = LoadDelays();
if (delays != null && (delays.Length == 0 || delays.Any(d => d < 0)))
    delays = null; // fall back to default backoff
attribute.DelaysInSeconds = delays;

Type guard

static bool IsValidDelays(int[] value) =>
    value == null || (value.Length > 0 && value.All(d => d >= 0));

Prevention

When it happens

Trigger: Setting [AutomaticRetry(DelaysInSeconds = new[]{-5, 10})] or DelaysInSeconds = new int[0]. A null assignment is permitted (uses default backoff); only non-null arrays with empty/negative elements throw.

Common situations: Loading delay values from JSON/YAML config that maps missing values to -1 or 0-length arrays; mixing up the order of delays; intending 'no delay' but using -1 instead of 0.

Related errors


AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13). Data as JSON: /api/errors/c0b9be10b59b3588. Report an issue: GitHub.