{"record":{"id":"2c1f0616af4161f4","repo":"stride3d/stride","slug":"cast-from-v1-to-m2-is-not-implemented-even-though-it-should","errorCode":null,"errorMessage":"Cast from {v1} to {m2} is not implemented (even though it should be valid since number of components is same","messagePattern":"Cast from (.+?) to (.+?) is not implemented \\(even though it should be valid since number of components is same","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":569,"sourceCode":"                }\n            case (VectorType v1, VectorType v2) when v1.Size == v2.Size:\n                values[0] = valueId;\n                break;\n            case (VectorType v1, VectorType v2) when v1.Size < v2.Size:\n                throw new InvalidOperationException($\"Can't cast from {v1} to {v2} (more components)\");\n            case (VectorType v1, VectorType v2) when v1.Size > v2.Size:\n                {\n                    Span<int> valuesTemp = stackalloc int[v2.Size];\n                    for (int i = 0; i < v2.Size; ++i)\n                        Insert(new OpCompositeExtract(context.GetOrRegister(v1.BaseType), valuesTemp[i] = context.Bound++, valueId, [i]));\n                    valueType = new VectorType(v1.BaseType, v2.Size);\n                    values[0] = Insert(new OpCompositeConstruct(context.GetOrRegister(valueType), context.Bound++, new LiteralArray<int>(valuesTemp))).ResultId;\n                    break;\n                }\n            case (VectorType v1, MatrixType m2) when v1.Size != m2.Rows * m2.Columns:\n                throw new InvalidOperationException($\"Can't cast from {v1} to {m2}\");\n            case (VectorType v1, MatrixType m2) when v1.Size == m2.Rows * m2.Columns:\n                throw new NotImplementedException($\"Cast from {v1} to {m2} is not implemented (even though it should be valid since number of components is same\");\n            case (MatrixType m1, ScalarType s2):\n                values[0] = Insert(new OpCompositeExtract(context.GetOrRegister(m1.BaseType), context.Bound++, valueId, [0, 0])).ResultId;\n                break;\n            case (MatrixType m1, VectorType v2) when v2.Size != m1.Rows * m1.Columns:\n                throw new InvalidOperationException($\"Can't cast from {m1} to {v2}\");\n            case (MatrixType m1, VectorType v2) when v2.Size == m1.Rows * m1.Columns:\n                throw new NotImplementedException($\"Cast from {m1} to {v2} is not implemented (even though it should be valid since number of components is same\");\n            case (MatrixType m1, MatrixType m2) when m1.Rows < m2.Rows || m1.Columns < m2.Columns:\n                throw new InvalidOperationException($\"Can't cast from {m1} to {m2} (larger matrix)\");\n            case (MatrixType m1, MatrixType m2) when m1.Rows >= m2.Rows && m1.Columns >= m2.Columns:\n                {\n                    // Extract each of the m2.Columns leading matrix columns, and shorten it from\n                    // m1.Rows down to m2.Rows components when the column vectors also shrink.\n                    Span<int> shuffleIndices = stackalloc int[m2.Rows];\n                    for (int j = 0; j < m2.Rows; ++j)\n                        shuffleIndices[j] = j;\n                    for (int i = 0; i < m2.Columns; ++i)\n                    {","sourceCodeStart":551,"sourceCodeEnd":587,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L551-L587","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rewrite the shader to construct the matrix explicitly from vector components instead of casting.","Implement the missing branch in Builder.Expressions.cs (build the matrix with OpCompositeConstruct/OpVectorShuffle from the vector's components).","Check/update Stride to a version where this cast is implemented."],"exampleFix":"// before (shader)\nfloat2x2 m = (float2x2)v4;\n// after\nfloat2x2 m = float2x2(v4.xy, v4.zw);","handlingStrategy":"fallback","validationCode":"// avoid the path entirely in shader source\nbool vecToMatCastImplemented = false; // known Stride limitation; avoid (floatNxM)vec casts","typeGuard":"bool IsUnsupportedVecToMat(SymbolType from, SymbolType to) => from is VectorType v && to is MatrixType m && v.Size == m.Rows * m.Columns;","tryCatchPattern":"// around shader compilation\ntry { Compile(shader); }\ncatch (NotImplementedException e) { Log.Warn(e.Message); /* rewrite shader or fail with clear message */ }","preventionTips":["Never rely on vector->matrix implicit casts in HLSL sources compiled through Stride.","Construct matrices explicitly from components.","Track Stride releases for implementation of this cast."],"tags":["spirv","not-implemented","type-cast","shader-compilation"],"backgroundTag":"method-not-implemented","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}