stride3d/stride · error · NotImplementedException

Couldn't handle operand kind

Error message

Couldn't handle operand kind {logOp.Kind}

What it means

ParseCurrent materializes the current operand as (name, kind, words slice). Within a parameters table (Count > 0), the inner switch handles Pair* kinds, LiteralString, and generic kinds; anything else — a null/unknown kind not present in the parameters dictionary resolution, or a parameter entry with no matched arm — throws. Called by Current for each operand.

Solutions

  1. Inspect logOp.Kind at the throw and add a switch arm for it (e.g. LiteralContextDependentNumber or other exotic kinds).
  2. Update embedded grammar/OpData tables to the SPIR-V spec version matching the input module.
  3. Validate the module with spirv-val; if it's invalid, fix the producing toolchain instead.
  4. Patch ParseCurrent to fall back to consuming a single word for unknown kinds instead of throwing, if lossy parsing is acceptable.

Example fix

// before
_ => throw new NotImplementedException($"Couldn't handle operand kind {logOp.Kind}")
// after
{ Kind: OperandKind.LiteralContextDependentNumber } => new(n, k, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 1), wid),
_ => throw new NotImplementedException($"Couldn't handle operand kind {logOp.Kind}")
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the operand kind is one ParseCurrent handles:
if (logOp.Kind is null or OperandKind.None)
    throw new NotSupportedException("Operand kind not populated in grammar tables");

Type guard

static bool IsParsableKind(OperandKind? k) => k is OperandKind.LiteralString
    or OperandKind.PairIdRefIdRef or OperandKind.PairIdRefLiteralInteger
    or OperandKind.PairLiteralIntegerIdRef or not null and not OperandKind.None;

Try / catch

try { var operand = enumerator.Current; }
catch (NotImplementedException ex) when (ex.Message.StartsWith("Couldn't handle operand kind")) { /* skip or manually parse this operand; record the kind */ }

Prevention

When it happens

Trigger: Parsing an instruction whose operand parameters table contains an entry whose Kind is neither a Pair* kind nor LiteralString nor a plain recognized kind — i.e. logOp.Kind resolves to null/OperandKind.None or an exotic kind inside the parameters path.

Common situations: New SPIR-V grammar versions introducing operand kinds the parser's switch doesn't enumerate; entries in the parameters dictionary with unset Kind fields; modules using extensions with custom operand kinds.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Spirv/Parsing/OpDataEnumerator.cs:145

        }
    }

    public SpvOperand ParseCurrent()
    {
        var logOp = logicalOperands[oid];

        return logOp switch
        {
            { Parameters: OperandParameters { Count: > 0 } } when pid == -1 =>
                new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 1), wid, true),
            { Parameters: OperandParameters { Count: > 0 } p } when p.ContainsKey(new(logOp.Kind ?? OperandKind.None, Operands[startOperand])) && pid < p[new(logOp.Kind ?? OperandKind.None, Operands[startOperand])].Length =>
            p[new(logOp.Kind ?? OperandKind.None, Operands[startOperand])][pid] switch
            {
                { Name: string n, Kind: OperandKind k } when k.ToString().StartsWith("Pair") => new(n, k, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 2), wid),
                { Name: string n, Kind: OperandKind.LiteralString } => new(n, OperandKind.LiteralString, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, Operands[wid..].LengthOfString()), wid),
                { Name: string n, Kind: OperandKind k } => new(n, k, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 1), wid),
                _ => throw new NotImplementedException($"Couldn't handle operand kind {logOp.Kind}")
            },
            { Quantifier: OperandQuantifier.One, Kind: OperandKind.PairIdRefIdRef or OperandKind.PairIdRefLiteralInteger or OperandKind.PairLiteralIntegerIdRef } l
                => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 2), wid),
            { Quantifier: OperandQuantifier.One, Kind: OperandKind.LiteralString } => new(logOp.Name, OperandKind.LiteralString, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, Operands[wid..].LengthOfString()), wid),
            { Quantifier: OperandQuantifier.One, Kind: _ } => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 1), wid),
            { Quantifier: OperandQuantifier.ZeroOrOne, Kind: OperandKind.PairIdRefIdRef or OperandKind.PairIdRefLiteralInteger or OperandKind.PairLiteralIntegerIdRef }
                => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, 2), wid),
            { Quantifier: OperandQuantifier.ZeroOrOne, Kind: OperandKind.LiteralString }
                => new(logOp.Name, OperandKind.LiteralString, logOp.Quantifier ?? OperandQuantifier.One, Operands.Slice(wid, Operands[wid..].LengthOfString()), wid),
            { Quantifier: OperandQuantifier.ZeroOrOne, Kind: _ }
                => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, wid < Operands.Length ? Operands.Slice(wid, 1) : []),
            { Quantifier: OperandQuantifier.ZeroOrMore, Kind: OperandKind.PairIdRefIdRef or OperandKind.PairIdRefLiteralInteger or OperandKind.PairLiteralIntegerIdRef }
                => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, wid < Operands.Length ? Operands[wid..] : [], wid),
            { Quantifier: OperandQuantifier.ZeroOrMore, Kind: OperandKind.LiteralString }
                => throw new Exception("params of strings is not yet implemented"),
            { Quantifier: OperandQuantifier.ZeroOrMore, Kind: _ }
                => new(logOp.Name, logOp.Kind ?? OperandKind.None, logOp.Quantifier ?? OperandQuantifier.One, wid < Operands.Length ? Operands[wid..] : [], wid),
            _ => throw new NotImplementedException()

View on GitHub (pinned to 96fad776d2)