stride3d/stride · error · InvalidOperationException

Can't process constant {i.Data.IdResult}

Error message

Can't process constant {i.Data.IdResult}

What it means

ResolveConstantValue is a throwing wrapper around TryGetConstantValue: when TryGetConstantValue returns false — meaning the constant's operands cannot yet be folded (e.g. operands are themselves unresolved, per the code comment about unresolved generics) or the instruction shape is unrecognized — it throws an InvalidOperationException naming the instruction's IdResult. It is for callers who know the constant must be resolvable at this point.

Solutions

  1. Call TryGetConstantValue first and only invoke ResolveConstantValue after generics are fully resolved.
  2. Defer constant evaluation until after generic substitution passes complete.
  3. Handle the constant kind in TryGetConstantValue (e.g. add OpConstantComposite support) if it is legitimately constant.

Example fix

// before
var v = context.ResolveConstantValue(opDataIndex); // InvalidOperationException during generic pass
// after
if (context.TryGetConstantValue(opDataIndex, out var v, out var typeId)) { /* use v */ } else { /* defer */ }
Defensive patterns

Strategy: validation

Validate before calling

if (!context.TryGetConstantValue(opDataIndex, out var v, out var typeId)) { DeferEvaluation(opDataIndex); return; }

Try / catch

try { value = context.ResolveConstantValue(i); } catch (InvalidOperationException ex) when (ex.Message.StartsWith("Can't process constant")) { DeferEvaluation(i); }

Prevention

When it happens

Trigger: Calling ResolveConstantValue on an OpConstant (or derived op like OpBitcast/OpIAdd) whose operand ids cannot be resolved yet due to unresolved generic arguments, or whose opcode shape TryGetConstantValue does not handle.

Common situations: Evaluating constants during generic instantiation where the operand constant belongs to a not-yet-substituted generic parameter; composite constants (OpConstantComposite) that the fold logic does not decompose.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

        throw new Exception("Cannot find constant instruction for id " + constantId);
    }

    public bool TryGetConstantValue(int constantId, [MaybeNullWhen(false)] out object value, out int typeId)
    {
        if (Buffer.TryGetInstructionById(constantId, out var constant))
        {
            return TryGetConstantValue(constant, out value, out typeId);
        }

        typeId = 0;
        value = null;
        return false;
    }

    public object ResolveConstantValue(OpDataIndex i)
    {
        if (!TryGetConstantValue(i, out var value, out _))
            throw new InvalidOperationException($"Can't process constant {i.Data.IdResult}");

        return value;
    }

    // Note: this will return false if constant can't be resolved yet (i.e. due to unresolved generics). If it is not meant to become a constant (even later), behavior is undefined.
    public bool TryGetConstantValue(OpDataIndex i, [MaybeNullWhen(false)] out object value, out int typeId)
    {
        typeId = 0;
        value = null;

        // Check for unresolved values
        if (i.Op == Specification.Op.OpGenericParameterSDSL || i.Op == Specification.Op.OpGenericReferenceSDSL)
        {
            return false;
        }

        if (i.Op == Specification.Op.OpConstantStringSDSL)
        {

View on GitHub (pinned to 96fad776d2)