{"record":{"id":"5a642e5482de0624","repo":"stride3d/stride","slug":"can-t-cast-from-m1-to-m2-larger-matrix","errorCode":null,"errorMessage":"Can't cast from {m1} to {m2} (larger matrix)","messagePattern":"Can't cast from (.+?) to (.+?) \\(larger matrix\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":578,"sourceCode":"                    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                    {\n                        values[i] = Insert(new OpCompositeExtract(context.GetOrRegister(new VectorType(m1.BaseType, m1.Rows)), context.Bound++, valueId, [i])).ResultId;\n                        if (m1.Rows != m2.Rows)\n                        {\n                            values[i] = Insert(new OpVectorShuffle(context.GetOrRegister(new VectorType(m1.BaseType, m2.Rows)), context.Bound++, values[i], values[i], new(shuffleIndices))).ResultId;\n                        }\n                    }\n                    valueType = new VectorType(m1.BaseType, m2.Rows);\n                    valueCount = m2.Columns;\n                    break;","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L560-L596","documentation":"Thrown by Builder.Expressions.Convert when casting between two matrix types where the source matrix has fewer rows or columns than the target (an upcast to a 'larger matrix'). Conversion only supports shrinking or same-shape matrices, so growing a matrix is rejected with InvalidOperationException.","triggerScenarios":"Calling Convert with (MatrixType, MatrixType) where m1.Rows < m2.Rows || m1.Columns < m2.Columns, e.g. casting a 2x2 matrix to 3x3; reached via ConvertTexCoord, ConvertOffset, constant0/1, CompileSign, MultiplyConstant.","commonSituations":"Shader code widening matrices implicitly (e.g. assigning float2x2 into a float3x3 variable), unsupported in both HLSL semantics and this converter; usually indicates a shader type mistake.","solutions":["Fix the shader to use same-size or smaller target matrices.","Construct the larger matrix explicitly from the smaller one's rows/identity fill in shader code.","Verify the variable declarations in the shader match the intended math."],"exampleFix":"// before\nfloat3x3 m3 = (float3x3)m2;\n// after\nfloat3x3 m3 = float3x3(m2[0].xy0, m2[1].xy0, float3(0,0,1)); // explicit construction","handlingStrategy":"validation","validationCode":"bool canCastMatToMat(MatrixType from, MatrixType to) => from.Rows >= to.Rows && from.Columns >= to.Columns;","typeGuard":"bool IsMatUpcast(SymbolType from, SymbolType to) => from is MatrixType a && to is MatrixType b && (a.Rows < b.Rows || a.Columns < b.Columns);","tryCatchPattern":null,"preventionTips":["Never widen matrices via casts in shader code.","Build larger matrices explicitly with identity fill.","Double-check matrix dimensions in assignments."],"tags":["spirv","type-cast","shader-compilation","matrix"],"backgroundTag":"incompatible-source-type","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"}