stride3d/stride · error · NotImplementedException
Can't cast between structures
Error message
Can't cast between structures (cast from {valueType} to {castType}) What it means
CanConvertScore computes an implicit-conversion score for overload/cast resolution. Struct types are excluded from conversion scoring because the builder does not implement struct-to-struct casts, so encountering a StructType on either side is treated as an unimplemented path and throws immediately.
Solutions
- Make the source and target struct types identical (same SymbolType)
- Explicitly convert field-by-field: construct the target struct from the source struct's members
- Reinterpret via a helper that builds the new struct value instead of relying on cast
- If this should be supported, implement struct conversion logic in CanConvertScore instead of throwing
Example fix
// before
TargetStruct t = sourceStruct; // cast between structures
// after
TargetStruct t = new TargetStruct { A = sourceStruct.A, B = sourceStruct.B }; Defensive patterns
Strategy: type-guard
Validate before calling
if (valueType is StructType || castType is StructType)
return; // skip conversion scoring; require exact type match Type guard
bool IsCastable(SymbolType v, SymbolType c) => v is not StructType && c is not StructType;
Try / catch
try { score = CanConvertScore(valueType, castType); }
catch (NotImplementedException ex) when (ex.Message.Contains("cast between structures"))
{ /* require exact struct type or convert field-by-field */ } Prevention
- Match struct types exactly in shader APIs
- Avoid casts involving user-defined structs
- Convert structs explicitly via member-wise construction
When it happens
Trigger: Implicit conversion scoring where either the source or target SymbolType is a StructType and the types differ (e.g. passing a struct where another struct type is expected, triggering conversion ranking).
Common situations: Passing one user-defined struct type where a different (though field-compatible) struct is expected; API changes where a method parameter changed struct type; generics instantiation producing two distinct struct types.
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 between array of different sizes
- Can't cast between array of different types
- Can't cast from to (more components)
- 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/6f0e74c996c919ef.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:391
(Operator.GreaterOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThanEqual,
(Operator.GreaterOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThanEqual,
_ => throw new NotImplementedException($"Binary operator {op} not supported for element type {elementType}")
};
/// <summary>
/// Check if a type can be converted to another.
/// </summary>
/// <param name="valueType"></param>
/// <param name="castType"></param>
/// <returns>0 if perfect match, int.MaxValue if failure, a score higher than 0 otherwise.</returns>
public static int CanConvertScore(SymbolType valueType, SymbolType castType)
{
if (castType == valueType)
return 0;
if (castType is StructType || valueType is StructType)
throw new NotImplementedException($"Can't cast between structures (cast from {valueType} to {castType})");
if (castType is ArrayType a1 && valueType is ArrayType a2)
{
if (a1.BaseType == a2.BaseType)
{
if (a1.Size != -1 && a1.Size != a2.Size)
return int.MaxValue;
// Some sizes are undetermined; this can only happen during compilation due to incomplete generics type
// TODO: do a "check pass" later to make sure this won't happen after generics instantiation?
return 0;
}
else
{
return int.MaxValue;
}
}
if (castType is StreamsType { Kind: var targetKind }View on GitHub (pinned to 96fad776d2)