stride3d/stride · error · InvalidOperationException

Can't cast between array of different types

Error message

Can't cast between array of different types (cast from {valueType} to {castType})

What it means

When converting between array types whose base element types differ (e.g. int[] to float[]), Convert has no per-element lowering and throws InvalidOperationException. Array casts are only permitted when base types are identical (and sizes match).

Solutions

  1. Convert the array element-by-element into a new array of the target element type
  2. Change the source array to the target element type at construction
  3. Loosen the receiving API to accept the source element type
  4. Add element-wise conversion support to Convert if this cast should be legal

Example fix

// before
float[] f = (float[])intArray; // different element types
// after
var f = new float[intArray.Length];
for (int i = 0; i < intArray.Length; i++) f[i] = (float)intArray[i];
Defensive patterns

Strategy: type-guard

Validate before calling

if (valueType is ArrayType s && castType is ArrayType d && s.BaseType != d.BaseType)
    throw new InvalidOperationException("Convert array elements explicitly before casting");

Type guard

bool ArrayBaseTypesMatch(ArrayType a, ArrayType b) => a.BaseType == b.BaseType;

Try / catch

try { converted = Builder.Convert(value, castType); }
catch (InvalidOperationException ex) when (ex.Message.Contains("array of different types"))
{ /* convert per-element into a new array instead */ }

Prevention

When it happens

Trigger: Calling Convert where both types are ArrayType but a1.BaseType != a2.BaseType.

Common situations: Casting an int array to a float array in shader code; texture offset/coordinate helpers receiving arrays of the wrong element type; API changes that altered array element type without updating callers.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:508

        if (castType == valueType)
            return value;

        if (castType is StructType || valueType is StructType)
            throw new NotImplementedException($"Can't cast between structures (cast from {valueType} to {castType})");

        if (castType is ArrayType a1 && valueType is ArrayType a2)
        {
            if (a1.BaseType == a2.BaseType)
            {
                if (a1.Size != -1 && a1.Size != a2.Size)
                    throw new InvalidOperationException(($"Can't cast between array of different sizes (cast from {valueType} to {castType})"));
                // Some sizes are undetermined; this can only happen during compilation due to incomplete generics type
                // TODO: do a "check pass" later to make sure this won't happen after generics instantiation?
                return value;
            }
            else
            {
                throw new InvalidOperationException(($"Can't cast between array of different types (cast from {valueType} to {castType})"));
            }
        }

        if (castType is StreamsType { Kind: var targetKind }
            && valueType is StreamsType { Kind: var sourceKind }
            // Note: order is Input, Streams, Output
            && targetKind > sourceKind)
        {
            return new(InsertData(new OpCopyLogical(context.GetOrRegister(castType), context.Bound++, value.Id)));
        }

        // We don't support cast with object yet, filter for numeral types
        if ((castType is not ScalarType && castType is not VectorType && castType is not MatrixType)
            || (valueType is not ScalarType && valueType is not VectorType && valueType is not MatrixType))
            throw new NotImplementedException($"Cast only work between numeral types (cast from {valueType} to {castType})");

        // One entry per column of the SPIR-V matrix (i.e. per HLSL row), since MatrixType.Columns
        // is the OpTypeMatrix column count and MatrixType.Rows the size of each column vector.

View on GitHub (pinned to 96fad776d2)