dotnet/wpf · error · ArgumentOutOfRangeException
timeout
Error message
timeout
What it means
Dispatcher.Invoke validates the TimeSpan timeout argument and throws ArgumentOutOfRangeException (message shown as the parameter name 'timeout') when the timeout is negative and not exactly TimeSpan.FromMilliseconds(-1). -1 is the sentinel meaning 'infinite timeout'; any other negative value is rejected.
Solutions
- Pass TimeSpan.FromMilliseconds(-1) for an infinite timeout, or a non-negative TimeSpan.
- Clamp the timeout: if (ts < TimeSpan.Zero) ts = TimeSpan.FromMilliseconds(-1);
- Fix the calculation producing the negative TimeSpan (elapsed deadlines, subtraction order).
- Use the Invoke overloads without a timeout parameter when a default is acceptable.
Example fix
// before dispatcher.Invoke(action, DispatcherPriority.Normal, TimeSpan.FromSeconds(-1)); // after dispatcher.Invoke(action, DispatcherPriority.Normal, TimeSpan.FromMilliseconds(-1)); // infinite
Defensive patterns
Strategy: validation
Validate before calling
if (timeout < TimeSpan.Zero && timeout != TimeSpan.FromMilliseconds(-1))
timeout = TimeSpan.FromMilliseconds(-1); // or clamp to Zero
dispatcher.Invoke(work, priority, timeout); Prevention
- Use TimeSpan.FromMilliseconds(-1) as the only negative timeout (infinite sentinel)
- Clamp or normalize computed TimeSpans before passing to Invoke
- Verify DateTime arithmetic used to derive remaining timeouts cannot go negative
- Prefer timeout-less Invoke overloads when the default is acceptable
When it happens
Trigger: Calling Dispatcher.Invoke(cb, priority, timeout, ...) with a negative TimeSpan such as TimeSpan.FromSeconds(-1) or TimeSpan.FromMilliseconds(-500); passing a computed TimeSpan that came out negative.
Common situations: Computing a remaining timeout from a deadline that already elapsed; typos like -TimeSpan.FromSeconds(5); migrating code that used 0/-1 int milliseconds into TimeSpan overloads with a stray negative.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Specified argument was out of the range of valid values…
- SR.AutomationTimeout
- The operation has timed out.
- Argument out of range (end not contained in view)
- Argument out of range (position does not map to a line)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/2199c26a9cf4b4cf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:571
/// A cancellation token that can be used to cancel the operation.
/// If the operation has not started, it will be aborted when the
/// cancellation token is canceled. If the operation has started,
/// the operation can cooperate with the cancellation request.
/// </param>
/// <param name="timeout">
/// The minimum amount of time to wait for the operation to start.
/// Once the operation has started, it will complete before this method
/// returns.
/// </param>
public void Invoke(Action callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
{
ArgumentNullException.ThrowIfNull(callback);
ValidatePriority(priority, "priority");
if( timeout.TotalMilliseconds < 0 &&
timeout != TimeSpan.FromMilliseconds(-1))
{
throw new ArgumentOutOfRangeException(nameof(timeout));
}
// Fast-Path: if on the same thread, and invoking at Send priority,
// and the cancellation token is not already canceled, then just
// call the callback directly.
if(!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
{
SynchronizationContext oldSynchronizationContext = SynchronizationContext.Current;
try
{
DispatcherSynchronizationContext newSynchronizationContext;
if(BaseCompatibilityPreferences.GetReuseDispatcherSynchronizationContextInstance())
{
newSynchronizationContext = _defaultDispatcherSynchronizationContext;
}
else
{View on GitHub (pinned to 81131a70a4)