stride3d/stride · error · InvalidOperationException

Can't cast from to

Error message

Can't cast from {v1} to {m2}

What it means

Thrown by Builder.Expressions.Convert when casting a SPIR-V vector value to a matrix type whose total component count (Rows*Columns) does not equal the vector's Size. The converter only supports casts where the element counts match exactly, so a shape mismatch is rejected with InvalidOperationException.

Solutions

  1. Fix the shader source so the vector length equals the target matrix Rows*Columns.
  2. Construct the matrix explicitly in the shader (e.g. float2x3(v.x, v.y, v.z, ...) with explicit components) instead of relying on implicit cast.
  3. If the sizes do match, upgrade: this branch currently throws NotImplementedException in Stride; check Stride version and patch Builder.Expressions.cs to implement the vector->matrix construct.

Example fix

// before (shader)
float2x2 m = (float2x2)myVec3;
// after
float2x2 m = float2x2(myVec3.xy, myVec3.xz); // explicit construction
Defensive patterns

Strategy: validation

Validate before calling

// before Convert: check shape compatibility
bool canCastVecToMat(VectorType v, MatrixType m) => v.Size == m.Rows * m.Columns;

Type guard

bool IsVecToMatCastable(SymbolType from, SymbolType to) => from is VectorType v && to is MatrixType m && v.Size == m.Rows * m.Columns;

Prevention

When it happens

Trigger: Calling Convert (directly or via ConvertTexCoord, ConvertOffset, constant0/1, CompileSign, MultiplyConstant) with a vector-to-matrix cast where vector.Size != m2.Rows * m2.Columns, e.g. casting vec4 to a 2x3 matrix.

Common situations: Shader source performing assignments between vectors and matrices of differing component counts (e.g. HLSL `(float2x2)v` where v is a float3), often after refactoring a shader's data types or misreading HLSL matrix semantics.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

                    valueType = v1.BaseType;
                    break;
                }
            case (VectorType v1, VectorType v2) when v1.Size == v2.Size:
                values[0] = valueId;
                break;
            case (VectorType v1, VectorType v2) when v1.Size < v2.Size:
                throw new InvalidOperationException($"Can't cast from {v1} to {v2} (more components)");
            case (VectorType v1, VectorType v2) when v1.Size > v2.Size:
                {
                    Span<int> valuesTemp = stackalloc int[v2.Size];
                    for (int i = 0; i < v2.Size; ++i)
                        Insert(new OpCompositeExtract(context.GetOrRegister(v1.BaseType), valuesTemp[i] = context.Bound++, valueId, [i]));
                    valueType = new VectorType(v1.BaseType, v2.Size);
                    values[0] = Insert(new OpCompositeConstruct(context.GetOrRegister(valueType), context.Bound++, new LiteralArray<int>(valuesTemp))).ResultId;
                    break;
                }
            case (VectorType v1, MatrixType m2) when v1.Size != m2.Rows * m2.Columns:
                throw new InvalidOperationException($"Can't cast from {v1} to {m2}");
            case (VectorType v1, MatrixType m2) when v1.Size == m2.Rows * m2.Columns:
                throw new NotImplementedException($"Cast from {v1} to {m2} is not implemented (even though it should be valid since number of components is same");
            case (MatrixType m1, ScalarType s2):
                values[0] = Insert(new OpCompositeExtract(context.GetOrRegister(m1.BaseType), context.Bound++, valueId, [0, 0])).ResultId;
                break;
            case (MatrixType m1, VectorType v2) when v2.Size != m1.Rows * m1.Columns:
                throw new InvalidOperationException($"Can't cast from {m1} to {v2}");
            case (MatrixType m1, VectorType v2) when v2.Size == m1.Rows * m1.Columns:
                throw new NotImplementedException($"Cast from {m1} to {v2} is not implemented (even though it should be valid since number of components is same");
            case (MatrixType m1, MatrixType m2) when m1.Rows < m2.Rows || m1.Columns < m2.Columns:
                throw new InvalidOperationException($"Can't cast from {m1} to {m2} (larger matrix)");
            case (MatrixType m1, MatrixType m2) when m1.Rows >= m2.Rows && m1.Columns >= m2.Columns:
                {
                    // Extract each of the m2.Columns leading matrix columns, and shorten it from
                    // m1.Rows down to m2.Rows components when the column vectors also shrink.
                    Span<int> shuffleIndices = stackalloc int[m2.Rows];
                    for (int j = 0; j < m2.Rows; ++j)
                        shuffleIndices[j] = j;

View on GitHub (pinned to 96fad776d2)