stride3d/stride · error · InvalidOperationException

Capacity must be a power of two

Error message

Capacity must be a power of two

What it means

The same Deque<T> capacity constructor further requires the capacity to be a power of two (1, 2, 4, 8, ...) so that index wrapping can use a bitmask (mask = capacity - 1). When int.IsPow2(capacity) is false it throws InvalidOperationException. Despite the exception type, this is invalid input: capacities like 3, 5, 100 are simply not supported by the ring-buffer layout.

Solutions

  1. Round up to the next power of two: BitOperations.RoundUpToPowerOf2((uint)capacity).
  2. Use an explicit power-of-two constant (1, 2, 4, 8, 16, ...).
  3. Wrap construction in a helper that validates/normalizes capacity once.

Example fix

// before
var deque = new Deque<Entity>(100); // throws: 100 is not a power of two

// after
var cap = Math.Max(1, (int)System.Numerics.BitOperations.RoundUpToPowerOf2((uint)100));
var deque = new Deque<Entity>(cap); // 128
Defensive patterns

Strategy: validation

Validate before calling

int capacity = requested < 1 ? 1 : (int)System.Numerics.BitOperations.RoundUpToPowerOf2((uint)requested);
var deque = new Deque<Entity>(capacity); // always a valid power of two

Try / catch

try
{
    var deque = new Deque<Entity>(capacity);
}
catch (InvalidOperationException)
{
    var deque2 = new Deque<Entity>(System.Numerics.BitOperations.RoundUpToPowerOf2((uint)Math.Max(1, capacity)));
}

Prevention

When it happens

Trigger: new Deque<T>(100) or any non-power-of-two literal; sizing the deque to an expected item count without rounding up; translating code from List<T>/Queue<T> whose capacity constructors accept arbitrary values.

Common situations: Pre-allocating 'expected count' capacities measured empirically (e.g. 100); porting generic queue code to Stride's Deque; configuration values written by hand without the power-of-two constraint in mind.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/785c04f3829d733a. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core/Collections/Dequeue.cs:77

    /// </summary>
    private int offset;

    /// <summary>
    /// Used to wrap around indices when incrementing outside buffer range
    /// </summary>
    private int mask;

    /// <summary>
    /// Initializes a new instance of the <see cref="Deque&lt;T&gt;"/> class with the specified capacity.
    /// </summary>
    /// <param name="capacity">The initial capacity. Must be a power of two greater than <c>0</c>.</param>
    public Deque(int capacity)
    {
        if (capacity < 1)
            throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be greater than 0.");

        if (int.IsPow2(capacity) == false)
            throw new InvalidOperationException("Capacity must be a power of two");

        buffer = new T[capacity];
        mask = buffer.Length - 1;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Deque&lt;T&gt;"/> class.
    /// </summary>
    public Deque()
        : this(DefaultCapacity)
    {
    }

    #region GenericListImplementations

    /// <summary>
    /// Gets a value indicating whether this list is read-only. This implementation always returns <c>false</c>.
    /// </summary>

View on GitHub (pinned to 96fad776d2)