dotnet/wpf · error · ArgumentOutOfRangeException
ArgumentOutOfRangeException (timeout was Duration.Automatic)
Error message
ArgumentOutOfRangeException (timeout was Duration.Automatic)
What it means
WriteableBitmap.TryLock validates the lock timeout before attempting to acquire the back buffer. Duration.Automatic is not a real duration (it means 'defer to animation'), so passing it cannot be honored as a wait time and the library throws ArgumentOutOfRangeException. Callers must pass Duration.Forever, a finite Duration, or omit it.
Solutions
- Pass Duration.Forever to wait indefinitely: bitmap.TryLock(Duration.Forever).
- Pass a concrete finite Duration such as new Duration(TimeSpan.FromMilliseconds(100)).
- Check the Duration with duration.HasTimeSpan / == Duration.Automatic before passing and substitute a real duration.
- Switch to the parameterless Lock() if you do not need timeout semantics.
Example fix
// before
if (!bitmap.TryLock(Duration.Automatic)) { ... }
// after
if (!bitmap.TryLock(Duration.Forever)) { ... } Defensive patterns
Strategy: validation
Validate before calling
if (timeout == Duration.Automatic) timeout = Duration.Forever; // or a concrete TimeSpan duration
if (!timeout.HasTimeSpan && timeout != Duration.Forever) throw new ArgumentException("timeout must be Forever or a finite duration"); Type guard
bool IsValidLockTimeout(Duration d) => d == Duration.Forever || d.HasTimeSpan;
Prevention
- Never pass Durations sourced from animations directly to locking APIs
- Default to Duration.Forever unless a real timeout is needed
- Centralize lock acquisition in one helper that sanitizes the timeout
When it happens
Trigger: Calling TryLock(Duration.Automatic) or TryLock(rect, Duration.Automatic) — typically because a Duration was built via Duration.Automatic or taken from an animation property instead of a concrete timespan.
Common situations: Developers copy a Duration from an animated/timeline property (which is often Automatic) and pass it to TryLock; also occurs when a shared helper builds Durations with default Automatic semantics.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- SR.Image_InsufficientBuffer
- SR.Image_InsufficientBufferSize
- SR.Image_InvalidArrayForPixel
- ArgumentNullException (buffer/sourceBuffer was IntPtr.Zero)
- Collection_BadRank
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/46c9f01de72afd02.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/WriteableBitmap.cs:230
/// <summary>
/// This method tries to lock the WriteableBitmap for the specified
/// timeout and increments the lock count if successful.
/// </summary>
/// <param name="timeout">
/// The amount of time to wait while trying to acquire the lock.
/// To block indefinitely pass Duration.Forever.
/// Duration.Automatic is an invalid value.
/// </param>
/// <returns>Returns true if the lock is now held, false otherwise.</returns>
public bool TryLock(Duration timeout)
{
WritePreamble();
TimeSpan timeoutSpan;
if (timeout == Duration.Automatic)
{
throw new ArgumentOutOfRangeException(nameof(timeout));
}
else if (timeout == Duration.Forever)
{
timeoutSpan = TimeSpan.FromMilliseconds(-1);
}
else
{
timeoutSpan = timeout.TimeSpan;
}
if (_lockCount == UInt32.MaxValue)
{
throw new InvalidOperationException(SR.Image_LockCountLimit);
}
if (_lockCount == 0)
{
// Try to acquire the back buffer by the supplied timeout, if the acquire call times out, return false.View on GitHub (pinned to 81131a70a4)