dotnet/efcore · error · ArgumentException

Timeout must be greater than or equal to zero. Provided time

Error message

Timeout must be greater than or equal to zero. Provided timeout: {seconds} seconds.

What it means

Thrown by SetCommandTimeout(TimeSpan) when the supplied timeout is negative (and not Timeout.InfiniteTimeSpan, which maps to 0). Command timeouts must be >= 0 seconds; the underlying ADO.NET DbCommand.CommandTimeout rejects negatives.

Source

Thrown at src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs:967

    ///         <see cref="SetCommandTimeout(DatabaseFacade,int?)" />.
    ///     </para>
    ///     <para>
    ///         See <see href="https://aka.ms/efcore-docs-connections">Connections and connection strings</see> for more information and examples.
    ///     </para>
    /// </remarks>
    /// <param name="databaseFacade">The <see cref="DatabaseFacade" /> for the context.</param>
    /// <param name="timeout">The timeout to use.</param>
    public static void SetCommandTimeout(this DatabaseFacade databaseFacade, TimeSpan timeout)
    {
        if (timeout == Timeout.InfiniteTimeSpan)
        {
            databaseFacade.SetCommandTimeout(0);
            return;
        }

        if (timeout < TimeSpan.Zero)
        {
            throw new ArgumentException(RelationalStrings.TimeoutTooSmall(timeout.TotalSeconds));
        }

        if (timeout.TotalSeconds > int.MaxValue)
        {
            throw new ArgumentException(RelationalStrings.TimeoutTooBig(timeout.TotalSeconds));
        }

        databaseFacade.SetCommandTimeout(Convert.ToInt32(timeout.TotalSeconds));
    }

    /// <summary>
    ///     Returns the timeout (in seconds) set for commands executed with this <see cref="DbContext" />.
    /// </summary>
    /// <remarks>
    ///     <para>
    ///         Note that the command timeout is distinct from the connection timeout, which is commonly
    ///         set on the database connection string.
    ///     </para>

View on GitHub (pinned to dbf9771522)

Solutions

  1. Pass Timeout.InfiniteTimeSpan for no timeout, or a non-negative TimeSpan.
  2. Clamp the configured value to >= 0 before calling SetCommandTimeout: TimeSpan.FromSeconds(Math.Max(0, seconds)).
  3. Validate configuration at startup and fail fast with a clear message instead of at query time.

Example fix

// before
db.Database.SetCommandTimeout(TimeSpan.FromSeconds(cfg.CommandTimeout)); // cfg.CommandTimeout = -5

// after
var seconds = Math.Max(0, cfg.CommandTimeout);
db.Database.SetCommandTimeout(seconds == 0
    ? Timeout.InfiniteTimeSpan
    : TimeSpan.FromSeconds(seconds));
Defensive patterns

Strategy: validation

Validate before calling

if (timeout < TimeSpan.Zero && timeout != Timeout.InfiniteTimeSpan)
    throw new ArgumentOutOfRangeException(nameof(timeout));
db.Database.SetCommandTimeout(timeout);

Type guard

static bool IsValidTimeout(TimeSpan t)
    => t == Timeout.InfiniteTimeSpan || (t >= TimeSpan.Zero && t.TotalSeconds <= int.MaxValue);

Prevention

When it happens

Trigger: Calling db.Database.SetCommandTimeout(negativeTimeSpan) (RelationalDatabaseFacadeExtensions.cs:965-967). Happens when a TimeSpan is computed from a misconfigured setting or arithmetic that underflows.

Common situations: Reading timeout from configuration that is unset/default -1; subtracting durations producing a negative; passing -1 seconds expecting infinite (use Timeout.InfiniteTimeSpan instead); misparsed int values.

Understand the failure class

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/ecaa5c0887505dc8. Report an issue: GitHub.