stride3d/stride · error · InvalidOperationException

Item belongs to another PriorityNodeQueue.

Error message

Item belongs to another PriorityNodeQueue.

What it means

PriorityNodeQueue tracks each PriorityQueueNode's Index so it can locate items in the heap. Enqueue throws InvalidOperationException('Item belongs to another PriorityNodeQueue.') when item.Index != -1, meaning the node is already enqueued (in this queue or another); a node can only live in one queue at a time.

Solutions

  1. Remove the item from its current queue (Dequeue or Remove) before enqueueing it elsewhere
  2. Update the priority in place if the queue supports it instead of re-enqueueing
  3. Create a fresh PriorityQueueNode for each enqueue
  4. Initialize/reset item.Index = -1 only after the node has truly left a queue

Example fix

// before
queue.Enqueue(existingNode); // throws if already in a queue
// after
if (existingNode.Index != -1)
    queue.Remove(existingNode); // or use the queue's update API
queue.Enqueue(existingNode);
Defensive patterns

Strategy: validation

Validate before calling

if (item.Index == -1) queue.Enqueue(item);

Try / catch

try { queue.Enqueue(item); } catch (InvalidOperationException) { /* item already queued: remove first or update in place */ }

Prevention

When it happens

Trigger: Enqueueing a PriorityQueueNode that is already in a queue (Index >= 0); reusing node instances across queues; enqueueing the same node twice after forgetting a Dequeue/Remove.

Common situations: Re-prioritizing an item by enqueueing a node still in the queue; pooling/sharing node objects across multiple queues; scheduler logic that re-adds tasks without removing them first.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/c29f80185b5b8527. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core/Collections/PriorityNodeQueue.cs:115

        item.Index = -1;
    }

    /// <summary>Add an element to the priority queue - O(log(n)) time operation.</summary>
    /// <param name="item">The item to be added to the queue</param>
    /// <returns>A node representing the item.</returns>
    public PriorityQueueNode<T> Enqueue(T item)
    {
        var result = new PriorityQueueNode<T>(item);
        Enqueue(result);
        return result;
    }

    /// <summary>Add an element to the priority queue - O(log(n)) time operation.</summary>
    /// <param name="item">The item to be added to the queue</param>
    public void Enqueue(PriorityQueueNode<T> item)
    {
        if (item.Index != -1)
            throw new InvalidOperationException("Item belongs to another PriorityNodeQueue.");

        // We add the item to the end of the list (at the bottom of the
        // tree). Then, the heap-property could be violated between this element
        // and it's parent. If this is the case, we swap this element with the 
        // parent (a safe operation to do since the element is known to be less
        // than it's parent). Now the element move one level up the tree. We repeat
        // this test with the element and it's new parent. The element, if lesser
        // than everybody else in the tree will eventually bubble all the way up
        // to the root of the tree (or the head of the list). It is easy to see 
        // this will take log(N) time, since we are working with a balanced binary
        // tree.
        var n = items.Count;
        items.Add(item);
        item.Index = n;
        while (n != 0)
        {
            var p = n / 2;    // This is the 'parent' of this item
            if (comparer.Compare(items[n].Value, items[p].Value) >= 0)

View on GitHub (pinned to 96fad776d2)