dotnet/wpf · error · InvalidOperationException

SR.Image_LockCountLimit

Error message

SR.Image_LockCountLimit

What it means

TryLock refuses to increment the lock count past UInt32.MaxValue. Every Lock/TryLock call must be balanced by Unlock; an unbalanced (or recursive re-entrant without unlock) locking pattern accumulates locks until the counter saturates, which is a programming bug, so the library throws InvalidOperationException with SR.Image_LockCountLimit.

Solutions

  1. Balance every Lock/TryLock with exactly one Unlock, ideally in a finally block.
  2. Wrap lock/unlock in IDisposable (using pattern) so exceptions cannot leak the lock.
  3. Audit for re-entrant locking in per-frame code paths.
  4. Reuse a single lock scope per frame instead of nested lock calls.

Example fix

// before
bitmap.Lock();
WritePixels(...);
if (error) return; // unlock lost
bitmap.Unlock();
// after
bitmap.Lock();
try { WritePixels(...); }
finally { bitmap.Unlock(); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (bitmap._lockCount unchecked) — not public; instead track your own acquire count and assert it stays small: Debug.Assert(myLockDepth < 100);

Try / catch

try { if (!bitmap.TryLock(Duration.Forever)) return; DoWork(); } finally { bitmap.Unlock(); }

Prevention

When it happens

Trigger: Calling TryLock/Lock repeatedly (e.g., in a render loop) without a matching Unlock, roughly 4 billion times, or leaking locks due to early returns in a try block that skips Unlock.

Common situations: Long-running WPF apps that lock WriteableBitmaps per frame and lose unlocks on exception paths; helpers that lock on the caller's behalf without unlocking.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5040b90415992fcf. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/WriteableBitmap.cs:243

            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.
                if (!AcquireBackBuffer(timeoutSpan, true))
                {
                    return false;
                }

                Int32Rect rect = new Int32Rect(0, 0, _pixelWidth, _pixelHeight);

                HRESULT.Check(UnsafeNativeMethods.WICBitmap.Lock(
                    WicSourceHandle,
                    ref rect,
                    LockFlags.MIL_LOCK_WRITE,
                    out _pBackBufferLock
                    ));

View on GitHub (pinned to 81131a70a4)