HangfireIO/Hangfire · error · ArgumentOutOfRangeException

Attempts value must be equal or greater than zero.

Error message

Attempts value must be equal or greater than zero.

What it means

The Attempts property on AutomaticRetryAttribute (and other retry attributes that reuse it) represents the maximum automatic retry count and must be non-negative. Setting it to a negative number throws ArgumentOutOfRangeException immediately at assignment time, before any job runs. This is input validation on a configuration property, not a runtime job-execution failure.

Source

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

            DelayInSecondsByAttemptFunc = DefaultDelayInSecondsByAttemptFunc;
            LogEvents = true;
            OnAttemptsExceeded = AttemptsExceededAction.Fail;
            Order = 20;
        }

        /// <summary>
        /// Gets or sets the maximum number of automatic retry attempts.
        /// </summary>
        /// <value>Any non-negative number.</value>
        /// <exception cref="ArgumentOutOfRangeException">The value in a set operation is less than zero.</exception>
        public int Attempts
        {
            get { lock (_lockObject) { return _attempts; } }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), @"Attempts value must be equal or greater than zero.");
                }

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

        /// <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
        {

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Set Attempts to 0 to disable retries, or a positive integer for the number of attempts.
  2. If you intended infinite retries, that is not supported — use a large finite number or implement a custom retry filter.
  3. Validate config-driven values before assigning: clamp negatives to 0 in your configuration loader.

Example fix

// before
[AutomaticRetry(Attempts = -1)]
public void Run() { }

// after
[AutomaticRetry(Attempts = 0)] // disable retries
public void Run() { }
Defensive patterns

Strategy: validation

Validate before calling

int attempts = LoadFromConfig();
if (attempts < 0) attempts = 0; // clamp before assigning
attribute.Attempts = attempts;

Type guard

static bool IsValidAttempts(int value) => value >= 0;

Prevention

When it happens

Trigger: Setting [AutomaticRetry(Attempts = -1)] (or assigning Attempts = -5) on a job method or globally via GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = -1 }). Any value < 0 triggers the guard.

Common situations: Misunderstanding Attempts as a retry count offset (setting -1 intending 'infinite' or 'none'); loading Attempts from configuration that parses an empty/invalid string to a negative; copying a value meant for DelaysInSeconds.

Related errors


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