AvaloniaUI/Avalonia · error · InvalidOperationException
Stack was empty.
Error message
Stack was empty.
What it means
InvalidOperationException "Stack was empty." thrown by PooledStack<T>.ThrowForEmptyStack(), called from Peek() and Pop() when the stack has zero elements (`(uint)(size-1) >= (uint)array.Length` is the bounds-safe empty check). It signals an attempt to read/remove from a drained stack rather than returning default. TryPeek/TryPop exist as the non-throwing alternatives.
Source
Thrown at src/Avalonia.Base/Collections/Pooled/PooledStack.cs:574
public T[] ToArray()
{
if (_size == 0)
return Array.Empty<T>();
T[] objArray = new T[_size];
int i = 0;
while (i < _size)
{
objArray[i] = _array[_size - i - 1];
i++;
}
return objArray;
}
private void ThrowForEmptyStack()
{
Debug.Assert(_size == 0);
throw new InvalidOperationException("Stack was empty.");
}
private void ReturnArray(T[]? replaceWith = null)
{
if (_array?.Length > 0)
{
try
{
_pool.Return(_array, clearArray: _clearOnFree);
}
catch (ArgumentException)
{
// oh well, the array pool didn't like our array
}
}
if (!(replaceWith is null))
{View on GitHub (pinned to 11c5427268)
Solutions
- Use TryPop/TryPeek which return false instead of throwing.
- Guard with `if (stack.Count > 0)` before Peek/Pop.
- Bound the drain loop with `while (stack.Count > 0)`.
Example fix
// before
while (true)
DoWork(stack.Pop()); // throws when drained
// after
while (stack.TryPop(out var item))
DoWork(item); Defensive patterns
Strategy: validation
Validate before calling
if (!stack.TryPop(out var item))
return; // stack empty, handle gracefully
DoWork(item); Prevention
- Prefer TryPop/TryPeek over Pop/Peek when emptiness is possible.
- Guard drain loops with `while (stack.Count > 0)`.
- Document whether a method requires a non-empty stack at its entry.
When it happens
Trigger: Calling `stack.Peek()` or `stack.Pop()` on an empty PooledStack<T>; popping in a loop past the last element; consuming a stack that another code path already drained.
Common situations: A drain loop like `while (true) stack.Pop();` without a Count check; shared/multi-step processing where an earlier step emptied the stack; assuming a queue/stack is non-empty after a filter.
Related errors
- Collection was modified during enumeration.
- Enumeration was not started. | Enumeration has ended.
- Destination span is shorter than the list to be copied.
- array
- Destination too short.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/7a2d1b09e31b994a.
Report an issue: GitHub.