dotnet/wpf · error · InvalidOperationException

throw new…

Error message

throw new InvalidOperationException(SR.FrugalList_CannotPromoteBeyondArray);

What it means

FrugalObjectList<T>.Add hit an internal storage-promotion state it cannot handle. The frugal list stores items in escalating containers (1 item, 3 items, 6 items, then a growable array); if Add returns a store state beyond Array there is no larger container to promote into, so the library throws InvalidOperationException(FrugalList_CannotPromoteBeyondArray). This is effectively an internal invariant violation of the storage model, not something caller input normally causes.

Solutions

  1. Report as a WPF bug if hit from normal API use (dotnet/wpf repo) — caller code cannot fix the store state
  2. Update to the latest .NET/WPF servicing release, as frugal-collection bugs have been fixed over time
  3. Stop mutating shared WPF objects (e.g. a Style or ResourceDictionary) from multiple threads; concurrent mutation can corrupt list state
  4. As a workaround, replace the shared container with a fresh instance rather than continuing to Add into the failing one

Example fix

// before
style.Setters.Add(new Setter(...)); // throws CannotPromoteBeyondArray on a corrupted shared style
// after
var style = new Style(typeof(Button)) { BasedOn = sharedStyle };
style.Setters.Add(new Setter(...)); // mutate your own copy
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    list.Add(value);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("promote"))
{
    // corrupt internal store state: recreate the collection and log
    list = new FrugalObjectList<T>();
    list.Add(value);
}

Prevention

When it happens

Trigger: Calling Add on a FrugalObjectList<T> when the internal store's Add returns a FrugalListStoreState other than Success/ThreeItemList/SixItemList/Array (e.g. an unexpected or corrupted store state).

Common situations: Practically only seen inside WPF itself or when reflection/custom code has mutated the private _listStore; typical WPF property-system operations (styles, triggers, resource dictionaries) filling shared lists.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/FrugalList.cs:1789

                    // Insert the new item
                    newStore.Add(value);
                    _listStore = newStore;
                }
                else if (myState == FrugalListStoreState.Array)
                {
                    ArrayItemList<T> newStore = new ArrayItemList<T>(_listStore.Count + 1);

                    // Extract the values from the old store and insert them into the new store
                    newStore.Promote(_listStore);
                    _listStore = newStore;

                    // Insert the new item
                    newStore.Add(value);
                    _listStore = newStore;
                }
                else
                {
                    throw new InvalidOperationException(SR.FrugalList_CannotPromoteBeyondArray);
                }
            }

            return _listStore.Count - 1;
        }

        public void Clear()
        {
            _listStore?.Clear();
        }

        public bool Contains(T value)
        {
            if ((_listStore is not null) && (_listStore.Count > 0))
            {
                return _listStore.Contains(value);
            }

View on GitHub (pinned to 81131a70a4)