stride3d/stride · error · NotSupportedException
OpBitcast target scalar
Error message
OpBitcast target scalar {bitcastTargetScalar} is not supported What it means
After computing bitcastBits (a 32-bit uint), TryGetConstantValue reinterprets them as the target scalar: only Scalar.Int, Scalar.UInt, and Scalar.Float are supported; any other target scalar (e.g. Bool, Half, Int64, or Double) throws NotSupportedException 'OpBitcast target scalar ... is not supported'.
Solutions
- Restrict constant bitcasts to int/uint/float targets.
- Perform half/double bitcasts at runtime (emit the OpBitcast instruction rather than folding).
- Extend the target switch (e.g. Scalar.Half via bit manipulation, Scalar.Double via two 32-bit words).
Example fix
// before
value = bitcastTargetScalar switch { Scalar.Int => ..., Scalar.UInt => ..., Scalar.Float => ..., _ => throw ... };
// after
value = bitcastTargetScalar switch { Scalar.Int => ..., Scalar.UInt => ..., Scalar.Float => ..., Scalar.Double => BitConverter.UInt32BitsToDoublePair(bitcastBits), _ => throw ... }; Defensive patterns
Strategy: validation
Validate before calling
if (context.ReverseTypes[resultType] is ScalarType { Type: not (Scalar.Int or Scalar.UInt or Scalar.Float) }) EmitRuntimeInstruction(Specification.Op.OpBitcast); Type guard
bool IsFoldableBitcastTarget(ScalarType t) => t.Type is Scalar.Int or Scalar.UInt or Scalar.Float;
Try / catch
try { folded = context.GetConstantValue(bitcastId); } catch (NotSupportedException ex) when (ex.Message.Contains("target scalar")) { EmitRuntimeInstruction(Specification.Op.OpBitcast); } Prevention
- Restrict constant bitcasts to int/uint/float targets
- Emit half/double bitcasts as runtime instructions
- Validate target scalar kinds in your codegen before folding
When it happens
Trigger: Constant-folding an OpBitcast whose result type is a bool, half, 64-bit int/uint, or double scalar — the target-scalar switch's `_ =>` arm throws.
Common situations: Bitcasting to half/double for precision tricks, or to bool from comparison-style codegen, in constant subexpressions of generated shaders.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- OpBitcast operand type
- OpBitcast result type
- Unsupported binary op
- Unsupported conversion op
- Unsupported unary op
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/c3720cdb805813fd.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs:126
// Bitcast: reinterpret the operand's bits as the target scalar type.
case Specification.Op.OpBitcast:
if (!TryGetConstantValue(i.Data.Memory.Span[4], out var bitcastOperand, out _))
return false;
if (ReverseTypes[resultType] is not ScalarType { Type: var bitcastTargetScalar })
throw new NotSupportedException($"OpBitcast result type {ReverseTypes[resultType]} is not a scalar");
var bitcastBits = bitcastOperand switch
{
int v => (uint)v,
uint v => v,
float v => BitConverter.SingleToUInt32Bits(v),
_ => throw new NotSupportedException($"OpBitcast operand type {bitcastOperand.GetType()} is not supported"),
};
value = bitcastTargetScalar switch
{
Scalar.Int => (object)(int)bitcastBits,
Scalar.UInt => bitcastBits,
Scalar.Float => BitConverter.UInt32BitsToSingle(bitcastBits),
_ => throw new NotSupportedException($"OpBitcast target scalar {bitcastTargetScalar} is not supported"),
};
break;
// Unary operations
case Specification.Op.OpSNegate:
case Specification.Op.OpFNegate:
if (!TryGetConstantValue(i.Data.Memory.Span[4], out var unaryOperand, out var unaryOperandTypeId))
return false;
if (unaryOperandTypeId != resultType)
return false;
value = op switch
{
// Note: first cast to object is important, otherwise int/float will be cast as float
Specification.Op.OpSNegate => (object)(-(int)unaryOperand),
Specification.Op.OpFNegate => -(float)unaryOperand,
_ => throw new NotSupportedException($"Unsupported unary op: {op}"),
};
break;
// Binary operationsView on GitHub (pinned to 96fad776d2)