dotnet/efcore · error · ArgumentException
Timeout must be greater than or equal to zero. Provided…
Error message
Timeout must be greater than or equal to zero. Provided timeout: {seconds} seconds. What it means
Thrown by RelationalDatabaseFacadeExtensions.SetCommandTimeout(TimeSpan) when the supplied timeout is a negative TimeSpan (and is not Timeout.InfiniteTimeSpan, which is mapped to 0). Command timeouts must be zero or positive; a negative value is treated as a programming error.
Solutions
- Clamp the value to >= TimeSpan.Zero before calling (use Timeout.InfiniteTimeSpan for no limit, which maps to 0).
- Validate configuration: ensure timeout settings parse to a non-negative number.
- Pass an int seconds value via the SetCommandTimeout(int) overload after bounds-checking.
Example fix
// before
context.Database.SetCommandTimeout(TimeSpan.FromSeconds(cfg.Timeout)); // cfg.Timeout == -5 -> throws
// after
var ts = cfg.Timeout <= 0
? Timeout.InfiniteTimeSpan
: TimeSpan.FromSeconds(cfg.Timeout);
context.Database.SetCommandTimeout(ts); Defensive patterns
Strategy: validation
Validate before calling
// Clamp negative timeouts before calling SetCommandTimeout
TimeSpan ts = configuredTimeout;
if (ts == Timeout.InfiniteTimeSpan)
context.Database.SetCommandTimeout(0);
else if (ts < TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(configuredTimeout), "Timeout must be >= 0 or InfiniteTimeSpan.");
else if (ts.TotalSeconds > int.MaxValue)
context.Database.SetCommandTimeout(int.MaxValue);
else
context.Database.SetCommandTimeout(ts); Prevention
- Validate timeout config parses to a non-negative value.
- Use Timeout.InfiniteTimeSpan to mean 'no limit' (mapped to 0).
- Default uninitialized timeout fields to a sane positive value.
When it happens
Trigger: Calling Database.SetCommandTimeout(TimeSpan) with a value less than TimeSpan.Zero, e.g. TimeSpan.FromSeconds(-1), or a computed/overflowed negative duration.
Common situations: Deriving the timeout from configuration that parses to a negative number; subtracting durations to compute a remaining-time timeout that underflows; default/uninitialized TimeSpan fields passed by mistake.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timeout must be less than or equal to Int32.MaxValue…
- Relational-specific methods can only be used when the…
- Specified argument was out of the range of valid values…
- A call was made to ' ' that changed an option that must be…
- Cosmos-specific methods can only be used when the context…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/ecaa5c0887505dc8.
Report an issue: GitHub.
Appendix: 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 3a2006ef56)