stride3d/stride · error · NotImplementedException

Unsupported context dependent number with type

Error message

Unsupported context dependent number with type {typeInst.Op}

What it means

When resolving an OpConstant/OpSpecConstant, the type instruction found for the constant's type id must be OpTypeInt or OpTypeFloat for the value to be extracted as a number. Any other type opcode (OpTypeBool, OpTypeVector, OpTypePointer, etc.) throws NotImplementedException naming the type opcode. Composites are handled earlier in the method, so reaching here means an unexpected scalar-ish type.

Solutions

  1. Validate the SPIR-V module so constants of non-numerical types are not emitted as OpConstant (e.g. pointers use OpConstantNull/OpUndef paths)
  2. Add a case in TryGetConstantValue for the unexpected type opcode (e.g. route OpTypeBool to true/false handling)
  3. Check for parser bugs causing type-id lookup to resolve to the wrong instruction (dump typeInst.Op at the throw site)

Example fix

// before
else
    throw new NotImplementedException($"Unsupported context dependent number with type {typeInst.Op}");
// after
else if (typeInst.Op == Specification.Op.OpTypeBool)
{ value = operand.ToLiteral<byte>() != 0; return true; }
else
    throw new NotImplementedException($"Unsupported context dependent number with type {typeInst.Op}");
Defensive patterns

Strategy: validation

Validate before calling

// confirm a constant's result type is a numeric type before evaluation
bool IsNumericConstant(SpirvBuffer buffer, Instruction constant)
{
    var typeId = constant.Data.Memory.Span[1];
    return buffer.TryGetInstructionById(typeId, out var t) &&
           t.Op is Specification.Op.OpTypeInt or Specification.Op.OpTypeFloat;
}

Try / catch

try
{
    context.TryGetConstantValue(id, out var value, out var typeId);
}
catch (NotImplementedException ex) when (ex.Message.Contains("Unsupported context dependent number"))
{
    // handle composite/null constants through the dedicated paths instead
}

Prevention

When it happens

Trigger: A constant instruction whose Result Type is not an int/float/composite/bool type — e.g. an OpConstant typed as OpTypePointer, OpTypeStruct, or a mis-registered type id pointing to a non-number type instruction.

Common situations: Malformed or hand-written SPIR-V where constants are typed incorrectly; parser state where a type id resolves to the wrong instruction; modules with constants of types the evaluator never expected to see here.

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


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

Appendix: source

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

                    { 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)
    {
        var value = CompileConstantLiteral(literal);
        if (size == 1)
            return value;

        var type = new VectorType((ScalarType)ReverseTypes[value.TypeId], size);

View on GitHub (pinned to 96fad776d2)