stride3d/stride · error · InvalidOperationException

Swizzle is out of bound for expression of type

Error message

Swizzle {Accessors[i + 1]} is out of bound for expression {ToString(i)} of type {currentValueType}

What it means

In the second phase of swizzle coalescing, indices produced by combining swizzle1 and swizzle2 are validated against the vector size; if a combined index exceeds the component count, an InvalidOperationException is thrown naming the outer accessor (Accessors[i+1]) and the expression's type.

Solutions

  1. Ensure the outer swizzle letters fit the inner swizzle's component count (e.g. v.xy.yx, not v.xy.z)
  2. Reduce chained swizzles into a single swizzle in the shader source
  3. Validate swizzle letters against component counts before compiling

Example fix

// before
float2 v; float f = v.xy.z;
// after
float2 v; float f = v.xy.x;
Defensive patterns

Strategy: validation

Validate before calling

bool outerValid = outerSwizzle.All(c => "xyzw".IndexOf(c) < innerSwizzle.Length);

Type guard

bool ChainedSwizzleValid(string inner, string outer) => outer.All(c => "xyzw".IndexOf(c) < inner.Length);

Try / catch

try { Compile(expr); } catch (InvalidOperationException e) when (e.Message.Contains("is out of bound")) { ReportSwizzleError(expr, e.Message); }

Prevention

When it happens

Trigger: Chained swizzles where the OUTER swizzle selects beyond the result size of the inner swizzle, e.g. float2 v; v.xy.z — inner yields 2 components but outer index z=2 is out of range.

Common situations: Nested/double swizzles ported from other languages; generated shader code composing swizzles programmatically with mismatched lengths.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Expression.cs:926

                    VectorType v => (v.Size, v.BaseType),
                    _ => throw new NotSupportedException($"Unsupported type {vectorOrScalarType} for swizzle coalescing"),
                };

                var swizzleIndices = new int[swizzle1.Length];
                for (int j = 0; j < swizzle1.Length; ++j)
                {
                    swizzleIndices[j] = ConvertSwizzle(swizzle1[j]);
                    if (swizzleIndices[j] >= size)
                        throw new InvalidOperationException($"Swizzle {Accessors[i]} is out of bound for expression {ToString(i)} of type {vectorOrScalarType}");
                }

                // Combine swizzles with previous ones
                var newSwizzleIndices = new int[swizzle2.Length];
                for (int j = 0; j < swizzle2.Length; ++j)
                {
                    newSwizzleIndices[j] = swizzleIndices[ConvertSwizzle(swizzle2[j])];
                    if (newSwizzleIndices[j] >= size)
                        throw new InvalidOperationException($"Swizzle {Accessors[i + 1]} is out of bound for expression {ToString(i)} of type {currentValueType}");
                }

                Accessors.RemoveAt(i + 1);
                Span<char> vectorFields = ['x', 'y', 'z', 'w'];
                Span<char> newSwizzle = stackalloc char[swizzle2.Length];
                for (int j = 0; j < swizzle2.Length; ++j)
                {
                    newSwizzle[j] = vectorFields[newSwizzleIndices[j]];
                }

                Accessors[i] = accessor = new Identifier(new(newSwizzle), default);
            }
        }

        // Some accessors push up to 2 values on the stack
        Span<int> accessChainIds = stackalloc int[Accessors.Count * 2];
        Span<int> swizzleBuffer = stackalloc int[4]; // max swizzle length

View on GitHub (pinned to 96fad776d2)