stride3d/stride · error · InvalidOperationException
Type of binary operation could not be determined
Error message
Type of binary operation could not be determined
What it means
After handling struct/array composite cases, BinaryOperation calls AnalyzeBinaryOperation to derive operand and result types. If it returns null (the operator/type combination is not analyzable, e.g. unsupported operator on those types), the builder throws InvalidOperationException 'Type of binary operation could not be determined'.
Solutions
- Check that the operator is valid for the operand types; cast operands to a supported type
- Use explicit type conversions so both sides resolve to a common scalar type
- Inspect AnalyzeBinaryOperation's return-null conditions for the given op/type combo
- Add shader-side explicit functions to implement unsupported operator semantics
Example fix
// before (HLSL) float a, b; var c = a & b; // after int ai = (int)a, bi = (int)b; var c = (float)(ai & bi);
Defensive patterns
Strategy: validation
Validate before calling
// Validate the operator/type combination is analyzable before codegen
if (AnalyzeBinaryOperation(table, leftType, op, rightType, info) is null)
throw new ShaderSemanticException($"Operator {op} is not defined for {leftType} and {rightType}"); Type guard
bool IsBinaryOpAnalyzable(SymbolTable t, SymbolType l, Operator op, SymbolType r, TextLocation loc) => AnalyzeBinaryOperation(t, l, op, r, loc) is not null;
Try / catch
try { var r = BinaryOperation(table, context, left, op, right, info); }
catch (InvalidOperationException ex) when (ex.Message == "Type of binary operation could not be determined") { throw new ShaderSemanticException($"Unsupported operator {op} for operand types", ex); } Prevention
- Use operators only where HLSL defines them for the operand types
- Insert explicit casts so operand types resolve to a common scalar
- Add analyzer tests for every operator/type pairing used in your shaders
When it happens
Trigger: A binary expression whose (leftType, op, rightType) combination makes AnalyzeBinaryOperation return null — e.g. an operator unsupported for the operand types (bitwise op on floats, % on non-integers, comparison on composites).
Common situations: Using an operator invalid for the operand types in HLSL (e.g. bitwise AND on float); applying comparison operators to struct/array types; mismatched scalar kinds the analyzer can't resolve.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unsupported type in array binary operation
- Unsupported type in struct binary operation
- 64bit integers
- Can't add type
- Can't write value on input or output struct
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/4c21b92ee42c57ca.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:282
{
var memberValue = Buffer.Insert(Position++, new OpCompositeExtract(context.GetOrRegister(arrayType.BaseType), context.Bound++, arrayValue.Id, [i])).ToValue();
var otherMemberValue = otherType switch
{
// If the other value is also a struct of same type, extract its value
ArrayType otherArrayType when otherArrayType == arrayType
=> Buffer.Insert(Position++, new OpCompositeExtract(context.GetOrRegister(arrayType.BaseType), context.Bound++, otherValue.Id, [i])).ToValue(),
ScalarType => otherValue,
_ => throw new NotSupportedException($"Unsupported type in array binary operation: {otherType}"),
};
arrayValues[i] = leftType is StructType
? BinaryOperation(table, context, memberValue, op, otherMemberValue, info, name).Id
: BinaryOperation(table, context, otherMemberValue, op, memberValue, info, name).Id;
}
return Buffer.Insert(Position++, new OpCompositeConstruct(context.GetOrRegister(arrayType), resultId, [.. arrayValues])).ToValue();
}
(var operandType, var resultType) = AnalyzeBinaryOperation(table, leftType, op, rightType, info) ?? throw new InvalidOperationException("Type of binary operation could not be determined");
// TODO: Some specific cases where one of the operands doesn't need to have exact same type as resultType (such as shift in OpShiftRightLogical, or signedness for some other operations)
// We'll need to review those cases
left = Convert(context, left, operandType);
right = Convert(context, right, operandType);
var resultTypeId = context.GetOrRegister(resultType);
// Refresh types (after convert)
leftType = context.ReverseTypes[left.TypeId];
rightType = context.ReverseTypes[right.TypeId];
// SPIR-V arithmetic ops (OpFAdd, OpFSub, OpFMul, etc.) only accept scalar/vector types.
// For matrices, decompose into column vectors, apply the op per-column, then reconstruct.
if (leftType is MatrixType matType)
{
if (op is not (Operator.Plus or Operator.Minus or Operator.Mul or Operator.Div))
throw new InvalidOperationException($"Operator '{op}' is not supported on matrix types");View on GitHub (pinned to 96fad776d2)