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

  1. Pass Duration.Forever to wait indefinitely: bitmap.TryLock(Duration.Forever).
  2. Pass a concrete finite Duration such as new Duration(TimeSpan.FromMilliseconds(100)).
  3. Check the Duration with duration.HasTimeSpan / == Duration.Automatic before passing and substitute a real duration.
  4. 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

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

Related errors


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)