stride3d/stride · error · InvalidOperationException
Unexpected type for f16tof32
Error message
Unexpected type {inputType} for f16tof32 What it means
CompileF32tof16's sibling f16tof32 expects its input to resolve to a uint or vector-of-uint (packed half values) so it can unpack via GLSL UnpackHalf2x16, extract components, and recompose. If the input type is anything else, it throws InvalidOperationException with the resolved input type, since the packed-half unpacking path cannot apply.
Solutions
- Ensure the argument is uint or a uint vector holding packed half values (asuint on the packed data).
- Reinterpret with asuint(...) if the bits are currently typed as something else.
- If you intended a plain float conversion, use a cast instead of f16tof32.
- If a new input kind (e.g. scalar uint handled separately) should be supported, extend CompileF16tof32's type dispatch.
Example fix
// before (SDSL) float x = 1.5; float y = f16tof32(x); // throws: Unexpected type float // after uint packed = asuint(...); float y = f16tof32(packed);
Defensive patterns
Strategy: validation
Validate before calling
bool IsPackedUint(TypeBase t) =>
t is ScalarType { Type: Scalar.UInt } or VectorType { BaseType: ScalarType { Type: Scalar.UInt } }; Type guard
bool IsUintOrUintVec(TypeBase t) => t.GetElementType() is ScalarType { Type: Scalar.UInt }; Try / catch
try { result = intrinsics.CompileF16tof32(table, ctx, builder, fnType, x); }
catch (InvalidOperationException ex) { /* report that input must be uint of packed halves */ } Prevention
- Remember f16tof32 takes uint(s) of packed half bits
- Use asuint() to reinterpret before unpacking
- Use plain casts for ordinary float conversions
When it happens
Trigger: Calling f16tof32(x) where x is float, int, half, or a vector whose element type is not uint — the intrinsic requires the packed 16-bit representation held in uint(s).
Common situations: Forgetting that HLSL f16tof32 takes a uint (or uint-vector) of packed halves and passing the original float/half value; assigning the result of an intermediate computation to a float variable and feeding it back.
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
- Unsupported element type for clamp
- Unsupported mul operand types
- Unsupported element type for saturate
- Unsupported element type for sign
- Unexpected type for f32tof16
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/9e89b04f983d078d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicImplementations.cs:417
else if (inputType is VectorType v)
{
var uintType = context.GetOrRegister(ScalarType.UInt);
var components = new int[v.Size];
for (int i = 0; i < v.Size; i++)
{
// Extract uint component
var comp = new SpirvValue(builder.InsertData(new OpCompositeExtract(uintType, context.Bound++, x.Id, [i])));
// UnpackHalf2x16 -> float2
var unpack = builder.Insert(new GLSLExp(float2Type, context.Bound++, context.GetGLSL(), comp.Id));
unpack.InstructionMemory.Span[4] = 62; // GLSLstd450 UnpackHalf2x16
// Extract .x -> float
var extract = new SpirvValue(builder.InsertData(new OpCompositeExtract(floatType, context.Bound++, unpack.ResultId, [0])));
components[i] = extract.Id;
}
var result = new SpirvValue(builder.InsertData(new OpCompositeConstruct(context.GetOrRegister(returnType), context.Bound++, [.. components])));
return result;
}
throw new InvalidOperationException($"Unexpected type {inputType} for f16tof32");
}
public override SpirvValue CompileF32tof16(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, TextLocation location = default)
{
// f32tof16(float) -> uint: PackHalf2x16(float2(x, 0.0)) -> uint
// For vector variants: decompose, apply per-element, recompose
var returnType = functionType.ReturnType;
var inputType = context.ReverseTypes[x.TypeId];
var float2Type = context.GetOrRegister(new VectorType(ScalarType.Float, 2));
var floatType = context.GetOrRegister(ScalarType.Float);
var uintType = context.GetOrRegister(ScalarType.UInt);
var zero = context.AddConstant(0.0f);
if (inputType is ScalarType)
{
// Construct float2(x, 0.0)
var float2Val = new SpirvValue(builder.InsertData(new OpCompositeConstruct(float2Type, context.Bound++, [x.Id, zero])));
// PackHalf2x16(float2) -> uint
var pack = builder.Insert(new GLSLExp(uintType, context.Bound++, context.GetGLSL(), float2Val.Id));View on GitHub (pinned to 96fad776d2)