stride3d/stride · error · NotSupportedException
Unsupported type in struct binary operation
Error message
Unsupported type in struct binary operation: {otherType} What it means
BinaryOperation on struct-typed values decomposes the operation member-by-member. For each member, the 'other' operand must be either a struct of the same type (to extract the matching member) or a scalar (broadcast). Any other type for the right-hand side is rejected with NotSupportedException.
Solutions
- Make both operands the same struct type, or convert one to a scalar/vector before the operation
- Perform the operation member-by-member explicitly in the shader
- Add an operator overload / conversion function for the mismatched combination
- Verify the struct definitions (fields, order, types) match exactly on both sides
Example fix
// before (HLSL)
struct S { float a; float b; };
S s; float3 v;
var r = s + v;
// after
S s2; S s3;
var r = s2 + s3; // or r.a = s.a + v.x; etc. Defensive patterns
Strategy: type-guard
Validate before calling
// Only allow struct+same-struct or struct+scalar binary ops
if (left is StructType st && right is not (StructType eq when eq == st) && right is not ScalarType)
throw new ShaderSemanticException($"Cannot apply operator between {left} and {right}"); Type guard
bool IsStructOpCompatible(StructType s, SymbolType other) => other is StructType o && o == s || other is ScalarType;
Try / catch
try { var r = BinaryOperation(table, context, left, op, right, info); }
catch (NotSupportedException ex) when (ex.Message.StartsWith("Unsupported type in struct binary operation")) { throw new ShaderSemanticException("Struct binary operations require same-type struct or scalar operand", ex); } Prevention
- Apply operators only between identical struct types or struct/scalar
- Implement explicit member-wise operations or operator overloads in shaders
- Keep struct definitions in sync across modules
When it happens
Trigger: Applying +,-,*,/ etc. between a struct value and a value of an incompatible type (different struct type, array, vector) via BinaryOperation when leftType is StructType.
Common situations: Shader code adding a struct to a vector or to a differently-shaped struct; operator overloads/typedefs changed so the two structs no longer match; API returning struct vs scalar inconsistently.
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
- Type of binary operation could not be determined
- Unsupported type in array binary operation
- 64bit integers
- Can't add type
- Can't cast between structures
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/08073e7ba2cb4d3e.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:243
// If there is a struct, we simply apply the operation for each member
// (this is SDSL-specific)
var structValue = leftType is StructType ? left : right;
var otherType = leftType is StructType ? rightType : leftType;
var otherValue = leftType is StructType ? right : left;
Span<int> structValues = stackalloc int[structType.Members.Count];
for (var i = 0; i < structType.Members.Count; i++)
{
var member = structType.Members[i];
var memberValue = Buffer.Insert(Position++, new OpCompositeExtract(context.GetOrRegister(member.Type), context.Bound++, structValue.Id, [i])).ToValue();
var otherMemberValue = otherType switch
{
// If the other value is also a struct of same type, extract its value
StructType otherStructType when otherStructType == structType
=> Buffer.Insert(Position++, new OpCompositeExtract(context.GetOrRegister(member.Type), context.Bound++, otherValue.Id, [i])).ToValue(),
ScalarType => otherValue,
_ => throw new NotSupportedException($"Unsupported type in struct binary operation: {otherType}"),
};
memberValue = leftType is StructType
? BinaryOperation(table, context, memberValue, op, otherMemberValue, info, name)
: BinaryOperation(table, context, otherMemberValue, op, memberValue, info, name);
structValues[i] = memberValue.Id;
}
return Buffer.Insert(Position++, new OpCompositeConstruct(context.GetOrRegister(structType), resultId, [.. structValues])).ToValue();
}
// Can indirectly happen inside struct (SDSL specific)
var arrayType = leftType as ArrayType ?? rightType as ArrayType;
if (arrayType != null)
{
var arrayValue = leftType is ArrayType ? left : right;
var otherType = leftType is ArrayType ? rightType : leftType;
var otherValue = leftType is ArrayType ? right : left;
View on GitHub (pinned to 96fad776d2)