microsoft/FASTER · error · InvalidOperationException

The list is empty!

Error message

The list is empty!

What it means

Dequeue on the single-buffer ElasticCircularBuffer found head == tail, which in this ring design means the buffer is empty. Since there is nothing to return, the library throws InvalidOperationException rather than returning a default value, making empty-state misuse explicit.

Solutions

  1. Check IsEmpty (or head/tail state) before calling Dequeue.
  2. Use TryDequeue-style logic or synchronize consumers with a lock/semaphore so only one thread dequeues per available item.
  3. In shutdown paths, signal consumers to stop polling before the buffer is drained empty.

Example fix

// before
var item = queue.Dequeue();

// after
if (!queue.IsEmpty())
{
    var item = queue.Dequeue();
}
Defensive patterns

Strategy: validation

Validate before calling

if (queue.IsEmpty()) return default; // or wait for signal
var item = queue.Dequeue();

Try / catch

try { item = queue.Dequeue(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("empty"))
{
    item = default; // queue drained; wait for producers
}

Prevention

When it happens

Trigger: Calling Dequeue when no items remain — e.g., a consumer thread draining faster than producers, or checking a count/emptiness condition incorrectly (or not at all) before dequeuing.

Common situations: Race between consumer threads both observing items then double-dequeuing; loops that call Dequeue until an exception instead of checking IsEmpty; shutdown ordering where consumers keep polling after producers stopped.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15). Data as JSON: /api/errors/a6fc1f7dd1ee9956. Report an issue: GitHub.

Appendix: source

Thrown at cs/remote/src/FASTER.common/ElasticCircularBuffer.cs:59

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Enqueue(ref T value)
        {
            int next = (tail + 1) & DefaultCapacity;
            if (next == head)
            {
                throw new InvalidOperationException("The inner list is full!");
            }
            Items[tail] = value;
            tail = next;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public T Dequeue()
        {
            if (head == tail)
            {
                throw new InvalidOperationException("The list is empty!");
            }
            int oldhead = head;
            head = (head + 1) & DefaultCapacity;
            var ret = Items[oldhead];
            Items[oldhead] = default;
            return ret;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsFull() => (((tail + 1) & DefaultCapacity) == head);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsEmpty() => (head == tail);

        public IEnumerable<T> Iterate()
        {
            int i = head;
            while (i != tail)

View on GitHub (pinned to 321d872eab)