stride3d/stride · error · InvalidOperationException
Can't cast from to (more components)
Error message
Can't cast from {v1} to {v2} (more components) What it means
In Convert's vector-to-vector conversion, growing a vector (source has fewer components than target) is not implemented: SPIR-V vector casts are handled by truncation (extracting leading components), not by extension with default values. A cast from a smaller vector to a larger one therefore throws InvalidOperationException.
Solutions
- Explicitly pad the smaller vector (e.g. float4(v.xy, 0, 1)) before conversion
- Truncate the larger side instead: change the target to the source's size
- Construct the target vector component-wise from the source components plus explicit fill values
- Update the calling helper (e.g. ConvertTexCoord) to accept the actual component count
Example fix
// before float4 p = (float4)texcoord2; // float2 -> float4 not allowed // after float4 p = float4(texcoord2, 0.0f, 1.0f); // explicit pad
Defensive patterns
Strategy: type-guard
Validate before calling
if (valueType is VectorType v1 && castType is VectorType v2 && v1.Size < v2.Size)
throw new InvalidOperationException($"Cannot grow vector {v1} to {v2}; pad explicitly"); Type guard
bool VectorSizeOk(VectorType src, VectorType dst) => src.Size >= dst.Size;
Try / catch
try { converted = Builder.Convert(value, castType); }
catch (InvalidOperationException ex) when (ex.Message.Contains("more components"))
{ /* pad the source vector explicitly before converting */ } Prevention
- Pad short vectors explicitly (float4(v, 0, 1)) rather than casting up
- Keep texcoord/offset vector widths consistent with sampling APIs
- Prefer truncation (larger→smaller) which Convert supports
When it happens
Trigger: Casting e.g. float2 to float4 through Convert — v1.Size < v2.Size triggers the throw (float4→float2 truncation is fine).
Common situations: Assigning a short vector (or texcoord/offset value) to a longer vector type; ConvertTexCoord/ConvertOffset receiving fewer components than the sampling API requires; implicit conversions attempted by overload resolution.
Related errors
- Can't cast between array of different sizes
- Can't cast between array of different types
- Can't cast between structures
- Cast only work between numeral types
- Binary operator not supported for element type
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/466100ed8c9f4fa0.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:556
values[0] = valueId;
break;
case (ScalarType s1, VectorType v2):
values[0] = valueId;
break;
case (ScalarType s1, MatrixType m2):
values[0] = valueId;
break;
case (VectorType v1, ScalarType s2):
{
values[0] = Insert(new OpCompositeExtract(context.GetOrRegister(v1.BaseType), context.Bound++, valueId, [0])).ResultId;
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}");View on GitHub (pinned to 96fad776d2)