stride3d/stride · error · InvalidOperationException
Can't cast from to
Error message
Can't cast from {m1} to {v2} What it means
Thrown by Builder.Expressions.Convert when casting a matrix to a vector whose Size does not equal the matrix's total component count (Rows*Columns). Only same-component-count matrix->vector casts are contemplated, so a mismatched shape is rejected with InvalidOperationException.
Solutions
- Adjust the shader so the target vector's size equals the matrix's Rows*Columns.
- Extract explicit rows/columns in the shader (e.g. `mul` results, m[0].xy) instead of casting the whole matrix.
- If a truncating cast is intended, perform it manually in shader code.
Example fix
// before float2 v = (float2)myMat3x3; // after float2 v = myMat3x3[0].xy; // or mul result
Defensive patterns
Strategy: validation
Validate before calling
bool canCastMatToVec(MatrixType m, VectorType v) => v.Size == m.Rows * m.Columns;
Type guard
bool IsMatToVecCastable(SymbolType from, SymbolType to) => from is MatrixType m && to is VectorType v && v.Size == m.Rows * m.Columns;
Prevention
- Match vector size to matrix Rows*Columns before casting.
- Extract explicit rows/columns instead of casting whole matrices.
- Review variable declarations when matrices and vectors interact.
When it happens
Trigger: Calling Convert with (MatrixType, VectorType) where v2.Size != m1.Rows * m1.Columns, e.g. casting a 3x3 matrix to a vec2; reached via ConvertTexCoord, ConvertOffset, constant0/1, CompileSign, MultiplyConstant.
Common situations: Shader code assigning a matrix into a smaller vector variable, or passing a matrix where a flattened vector of different length is expected, typically from HLSL/C# type inconsistencies after a refactor.
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
- Can't cast from to
- Cast from to is not implemented
- Cast from to is not implemented
- Can't cast from to (larger matrix)
- spirv_to_dxil_pipeline failed; SPIR-V dumped to
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/7cd72243aee291de.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:574
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)
{
values[i] = Insert(new OpCompositeExtract(context.GetOrRegister(new VectorType(m1.BaseType, m1.Rows)), context.Bound++, valueId, [i])).ResultId;
if (m1.Rows != m2.Rows)
{
values[i] = Insert(new OpVectorShuffle(context.GetOrRegister(new VectorType(m1.BaseType, m2.Rows)), context.Bound++, values[i], values[i], new(shuffleIndices))).ResultId;
}View on GitHub (pinned to 96fad776d2)