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
- Inspect logOp.Kind at the throw and add a switch arm for it (e.g. LiteralContextDependentNumber or other exotic kinds).
- Update embedded grammar/OpData tables to the SPIR-V spec version matching the input module.
- Validate the module with spirv-val; if it's invalid, fix the producing toolchain instead.
- 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
- Regenerate OpData tables from the same spirv.core.grammar.json version as the target modules.
- Check parameters dictionary entries for null Kind before enumeration.
- Reject or special-case extension/custom operand kinds before parsing.
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
- Couldn't handle operand
- kind is inexistent
- Invalid SPIR-V instruction
- params of strings is not yet implemented
- params of strings is not yet implemented
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)