{"record":{"id":"a972b8eee47708fe","repo":"stride3d/stride","slug":"cannot-parse-constant-expression-from-inst-op","errorCode":null,"errorMessage":"Cannot parse constant expression from {inst.Op}","messagePattern":"Cannot parse constant expression from (.+?)","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Core/ConstantExpression.cs","lineNumber":224,"sourceCode":"                    {\n                        var left = ParseFromBuffer(inst.Data.Memory.Span[4], buffer, context);\n                        var right = ParseFromBuffer(inst.Data.Memory.Span[5], buffer, context);\n                        return new BinaryOpExpr(op, left, right);\n                    }\n                    case Op.OpSelect:\n                    {\n                        var cond = ParseFromBuffer(inst.Data.Memory.Span[4], buffer, context);\n                        var trueVal = ParseFromBuffer(inst.Data.Memory.Span[5], buffer, context);\n                        var falseVal = ParseFromBuffer(inst.Data.Memory.Span[6], buffer, context);\n                        return new SelectExpr(cond, trueVal, falseVal);\n                    }\n                    default:\n                        throw new NotImplementedException($\"Unsupported OpSpecConstantOp inner op: {op}\");\n                }\n            }\n\n            default:\n                throw new NotImplementedException($\"Cannot parse constant expression from {inst.Op}\");\n        }\n    }\n}\n\n/// <summary>\n/// Integer constant. Covers int, uint, long, ulong — signedness determined at emission by SPIR-V type context.\n/// </summary>\npublic sealed record IntConstExpr(long Value) : ConstantExpression\n{\n    public override int Emit(SpirvContext context)\n    {\n        // For values that fit in int, use int (signed) — matches the common case for array sizes\n        if (Value is >= int.MinValue and <= int.MaxValue)\n            return context.CompileConstant((int)Value).Id;\n        return context.CompileConstant(Value).Id;\n    }\n\n    public override bool TryEvaluate(out object? value)","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Core/ConstantExpression.cs#L206-L242","documentation":"ConstantExpression.ParseInstruction (reached from ParseFromBuffer) converts SPIR-V instructions into constant expression AST nodes. It only supports a fixed set of opcodes (OpConstant, OpConstantComposite, OpSpecConstantOp with a known inner op, etc.). When the SPIR-V module contains a constant-producing opcode outside that set, the default arm throws this NotImplementedException instead of silently producing a wrong AST.","triggerScenarios":"Calling ParseFromBuffer/ParseFromBuffer on a SPIR-V instruction whose Op opcode is not one of the handled constant opcodes — e.g. OpSpecConstant (if unhandled), OpConstantNull, OpConstantTrue/False, or any new/extension constant opcode. The message echoes inst.Op so you can see which opcode is missing.","commonSituations":"Compiling shaders that use specialization constants or constant constructs the parser never saw before; feeding SPIR-V produced by a newer compiler (e.g. newer DXC/glslang) that emits constant opcodes this parser version doesn't handle; loading SPIR-V from extensions (float controls, ray tracing specialization) outside the supported set.","solutions":["Read the opcode from the exception message and add a case for it in ParseInstruction's switch in ConstantExpression.cs (handle it like the existing unary/binary/select arms).","If the opcode is legitimate but unsupported, implement parsing for that inner op of OpSpecConstantOp in the OpSpecConstantOp switch (the sibling 'Unsupported OpSpecConstantOp inner op' error points there).","As a workaround, rewrite the shader/module to avoid the unsupported constant construct (e.g. bake spec-constant values or use a supported constant form).","Upgrade to a Stride.Shaders.Parsers version whose parser covers the opcode, if available."],"exampleFix":"// before\ndefault:\n    throw new NotImplementedException($\"Cannot parse constant expression from {inst.Op}\");\n\n// after\ncase Op.OpConstantNull:\n    return new NullConstExpr(typeId);\ndefault:\n    throw new NotImplementedException($\"Cannot parse constant expression from {inst.Op}\");","handlingStrategy":"try-catch","validationCode":"// Only pass modules whose constant instructions use supported opcodes\nvar op = (Op)inst.Op;\nvar supported = new HashSet<Op> { Op.OpConstant, Op.OpConstantComposite, Op.OpSpecConstantOp /*, others handled in the switch */ };\nif (!supported.Contains(op))\n    throw new NotSupportedException($\"Module uses unparsed constant opcode {op}\");","typeGuard":"bool IsSupportedConstantOp(Op op) => op is Op.OpConstant or Op.OpConstantComposite or\n    (Op.OpSpecConstantOp and var s && IsSupportedSpecOp(s));","tryCatchPattern":"try\n{\n    var expr = ConstantExpression.ParseFromBuffer(resultId, buffer, context);\n}\ncatch (NotImplementedException ex) when (ex.Message.StartsWith(\"Cannot parse constant expression from\"))\n{\n    logger.LogWarning(ex, \"Unsupported SPIR-V constant opcode; skipping/failing this module\");\n    // fail the shader load or fall back to a non-constant path\n}","preventionTips":["Before parsing, scan the SPIR-V for OpSpecConstantOp inner opcodes and constant opcodes outside the supported set.","Pin the shader compiler (DXC/glslang) version so emitted constant opcodes match what the parser handles.","Write a unit test parsing each constant opcode family your shaders actually use.","Keep the opcode message in the exception — it names exactly which case to add."],"tags":["spirv","shader-parsing","not-implemented","constant-expression"],"backgroundTag":"method-not-implemented","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}