dotnet/efcore · error · InvalidOperationException

The specified 'CommandTimeout' value '{value}' is not valid.

Error message

The specified 'CommandTimeout' value '{value}' is not valid. It must be a positive number.

What it means

Thrown by RelationalOptionsExtension.WithCommandTimeout(int?) at line 167-169 when the supplied timeout is a negative integer. EF defines 0 as 'no timeout' and any positive value as seconds; negative values are meaningless. The guard is `commandTimeout is < 0`.

Source

Thrown at src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs:169

    }

    /// <summary>
    ///     The command timeout, or <see langword="null" /> if none has been set.
    /// </summary>
    public virtual int? CommandTimeout
        => _commandTimeout;

    /// <summary>
    ///     Creates a new instance with all options the same as for this instance, but with the given option changed.
    ///     It is unusual to call this method directly. Instead use <see cref="DbContextOptionsBuilder" />.
    /// </summary>
    /// <param name="commandTimeout">The option to change.</param>
    /// <returns>A new instance with the option changed.</returns>
    public virtual RelationalOptionsExtension WithCommandTimeout(int? commandTimeout)
    {
        if (commandTimeout is < 0)
        {
            throw new InvalidOperationException(RelationalStrings.InvalidCommandTimeout(commandTimeout));
        }

        var clone = Clone();

        clone._commandTimeout = commandTimeout;

        return clone;
    }

    /// <summary>
    ///     The maximum number of statements that will be included in commands sent to the database
    ///     during <see cref="DbContext.SaveChanges()" /> or <see langword="null" /> if none has been set.
    /// </summary>
    public virtual int? MaxBatchSize
        => _maxBatchSize;

    /// <summary>
    ///     Creates a new instance with all options the same as for this instance, but with the given option changed.

View on GitHub (pinned to dbf9771522)

Solutions

  1. Set CommandTimeout to 0 for unlimited/no timeout, or to a positive number of seconds.
  2. Validate the config value before passing it: use Math.Max(0, configuredValue).
  3. Check your appsettings.json / environment variable for a negative timeout value and correct it.

Example fix

// before
optionsBuilder.UseSqlServer(connStr, sql => sql.CommandTimeout(-1));

// after: 0 means no timeout
optionsBuilder.UseSqlServer(connStr, sql => sql.CommandTimeout(0));
Defensive patterns

Strategy: validation

Validate before calling

var timeout = configuration.GetValue<int?>("CommandTimeout") ?? 30;
if (timeout < 0) throw new ArgumentOutOfRangeException(nameof(timeout), "CommandTimeout must be >= 0");
optionsBuilder.UseSqlServer(connStr, sql => sql.CommandTimeout(timeout));

Try / catch

// Wrap external configuration reads
try { optionsBuilder.UseSqlServer(connStr, sql => sql.CommandTimeout(timeoutFromConfig)); }
catch (InvalidOperationException ex) when (ex.Message.Contains("CommandTimeout"))
{ logger.LogWarning(ex, "Invalid CommandTimeout in config, falling back to default"); }

Prevention

When it happens

Trigger: Calling optionsBuilder.UseSqlServer(connStr, sql => sql.CommandTimeout(-1)) or directly setting CommandTimeout to any value less than 0. Also happens when the timeout is read from configuration/appsettings with a misconfigured negative number.

Common situations: Reading CommandTimeout from a config file or environment variable that is misconfigured, or passing -1 intending 'infinite' (the correct infinite value is 0 in EF Core). Off-by-one errors in timeout calculation code.

Understand the failure class

Related errors


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