stride3d/stride · error · NotImplementedException

Unsupported float width

Error message

Unsupported float width {type.Width}

What it means

When resolving an OpConstant/OpSpecConstant whose type is OpTypeFloat, TryGetConstantValue maps Width 16/32/64 to Half/float/double. Any other float width throws NotImplementedException with the width in the message.

Solutions

  1. Re-emit the module with standard float widths (16/32/64)
  2. Extend the switch in TryGetConstantValue to handle the specific width (e.g. map Width 8 to a byte-based literal if required)
  3. Use standard half/float/double types in the shader source

Example fix

// before
{ Width: 64 } => operand.ToLiteral<double>(),
_ => throw new NotImplementedException($"Unsupported float width {type.Width}"),
// after
{ Width: 64 } => operand.ToLiteral<double>(),
{ Width: 8 } => operand.ToLiteral<byte>(), // custom handling if needed
_ => throw new NotImplementedException($"Unsupported float width {type.Width}"),
Defensive patterns

Strategy: validation

Validate before calling

bool IsSupportedFloatType(OpTypeFloat t) => t.Width is 16 or 32 or 64;

Type guard

bool IsSupportedFloatWidth(OpTypeFloat t) => t.Width is 16 or 32 or 64;

Try / catch

try
{
    context.TryGetConstantValue(id, out var value, out var typeId);
}
catch (NotImplementedException ex) when (ex.Message.StartsWith("Unsupported float width"))
{
    // re-export the shader with float16/32/64, or skip this constant
}

Prevention

When it happens

Trigger: Encountering an OpTypeFloat with a Width other than 16, 32, or 64 (e.g. Width 8, 24, or a non-power-of-two float encoding) during constant evaluation.

Common situations: Modules using non-standard float widths such as fp8 or float24 emitted by specialized toolchains; corrupted or hand-crafted SPIR-V binaries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/a23ec947f62fea4a. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs:235

                value = type switch
                {
                    { Width: <= 32, Signedness: 0 } => operand.ToLiteral<uint>(),
                    { Width: <= 32, Signedness: 1 } => operand.ToLiteral<int>(),
                    { Width: 64, Signedness: 0 } => operand.ToLiteral<ulong>(),
                    { Width: 64, Signedness: 1 } => operand.ToLiteral<long>(),
                    _ => throw new NotImplementedException($"Unsupported int width {type.Width}"),
                };
                return true;
            }
            else if (typeInst.Op == Specification.Op.OpTypeFloat)
            {
                var type = new OpTypeFloat(typeInst);
                value = type switch
                {
                    { Width: 16 } => operand.ToLiteral<Half>(),
                    { Width: 32 } => operand.ToLiteral<float>(),
                    { Width: 64 } => operand.ToLiteral<double>(),
                    _ => throw new NotImplementedException($"Unsupported float width {type.Width}"),
                };
                return true;
            }
            else
                throw new NotImplementedException($"Unsupported context dependent number with type {typeInst.Op}");
        }

        throw new Exception("Cannot find type instruction for id " + typeId);
    }

    public SpirvValue CreateDefaultConstantComposite(SymbolType type)
    {
        // TODO: cache results (either here or even more generally for any composite constant even if non-zero)
        return new(Buffer.AddData(new OpConstantNull(GetOrRegister(type), Bound++)));
    }

    public SpirvValue CreateConstantCompositeVectorRepeat(Literal literal, int size)
    {

View on GitHub (pinned to 96fad776d2)