stride3d/stride · error · NotImplementedException

Cast from to is not implemented

Error message

Cast from {v1} to {m2} is not implemented (even though it should be valid since number of components is same

What it means

Thrown by Builder.Expressions.Convert when casting a vector to a matrix of matching component count (v1.Size == m2.Rows*m2.Columns). The cast is recognized as valid, but the SPIR-V emission code for this shape has not been implemented yet, so a NotImplementedException is raised.

Solutions

  1. Rewrite the shader to construct the matrix explicitly from vector components instead of casting.
  2. Implement the missing branch in Builder.Expressions.cs (build the matrix with OpCompositeConstruct/OpVectorShuffle from the vector's components).
  3. Check/update Stride to a version where this cast is implemented.

Example fix

// before (shader)
float2x2 m = (float2x2)v4;
// after
float2x2 m = float2x2(v4.xy, v4.zw);
Defensive patterns

Strategy: fallback

Validate before calling

// avoid the path entirely in shader source
bool vecToMatCastImplemented = false; // known Stride limitation; avoid (floatNxM)vec casts

Type guard

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

Try / catch

// around shader compilation
try { Compile(shader); }
catch (NotImplementedException e) { Log.Warn(e.Message); /* rewrite shader or fail with clear message */ }

Prevention

When it happens

Trigger: Calling Convert with (VectorType, MatrixType) where the vector's Size equals the matrix Rows*Columns (e.g. vec4 -> 2x2 matrix); reached via ConvertTexCoord, ConvertOffset, CompileSign, MultiplyConstant, etc.

Common situations: Shader code performing HLSL-style vector-to-matrix casts like `(float2x2)v` with v being a float4; hit as an upstream Stride limitation rather than a user mistake.

Related errors


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

Appendix: source

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

                }
            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;
                    for (int i = 0; i < m2.Columns; ++i)
                    {

View on GitHub (pinned to 96fad776d2)