{"record":{"id":"147cb778231740c4","repo":"stride3d/stride","slug":"opcode-i-op-not-supported-when-compiling-constant-expression","errorCode":null,"errorMessage":"OpCode {i.Op} not supported when compiling constant {expression}","messagePattern":"OpCode (.+?) not supported when compiling constant (.+?)","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/ExpressionExtensions.cs","lineNumber":149,"sourceCode":"                var resultId = i.Data.Memory.Span[2];\n\n                // Try to fold: if all operands are known constants, compute the result at compile time.\n                if (TryFoldConstantOp(context, i, out var foldedInstruction))\n                {\n                    context.Add(foldedInstruction);\n                    result = new(resultId, resultType);\n                }\n                else\n                {\n                    Span<int> instruction = [(int)Op.OpSpecConstantOp, resultType, resultId, (int)i.Op, .. i.Data.Memory.Span[3..]];\n                    instruction[0] |= instruction.Length << 16;\n                    context.Add(new OpData(instruction));\n                    result = new(resultId, resultType);\n                }\n            }\n            else\n            {\n                throw new InvalidOperationException($\"OpCode {i.Op} not supported when compiling constant {expression}\");\n            }\n        }\n\n        buffer.Dispose();\n\n        return result;\n    }\n\n    /// <summary>\n    /// Returns true if the given ID refers to an OpConstant, OpConstantTrue, OpConstantFalse,\n    /// or OpConstantComposite (i.e. not a spec constant).\n    /// </summary>\n    private static bool IsPlainConstant(SpirvContext context, int id)\n    {\n        if (!context.GetBuffer().TryGetInstructionById(id, out var inst))\n            return false;\n        return inst.Op is Op.OpConstant or Op.OpConstantTrue or Op.OpConstantFalse or Op.OpConstantComposite or Op.OpConstantNull;\n    }","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/ExpressionExtensions.cs#L131-L167","documentation":"CompileConstantValue builds a SPIR-V constant for a parsed shader expression. It consumes instructions from a scratch buffer and expects each to be a constant-defining opcode; if the instruction has any other opcode, the compiler cannot represent the expression as a constant and throws InvalidOperationException.","triggerScenarios":"Calling CompileConstantValue on an expression whose compiled instruction stream contains a non-constant opcode (e.g. an instruction producing a result id that is not OpConstant/OpConstantComposite-family), typically after an expression that requires runtime evaluation was fed into a constant context.","commonSituations":"Using non-constant expressions (function calls, runtime math, stream reads) where SDSL expects a compile-time constant: array sizes, layout offsets, or constant initializers.","solutions":["Check the expression used in the constant context is genuinely compile-time constant (literals, constant composites)","If the value depends on runtime input, move it to a variable instead of a constant context","Use supported constant expressions only (e.g. simple arithmetic on constants) or extend CompileConstantValue to handle the missing opcode","Inspect the failing opcode name in the message to identify which SPIR-V instruction is unsupported"],"exampleFix":"// before\nconst int N = ComputeSize(); // function call in constant context\n// after\nconst int N = 16; // literal constant","handlingStrategy":"validation","validationCode":"bool IsCompileTimeConstant(SpirvInstruction i) => i.Op is OpCode.OpConstant or OpCode.OpConstantTrue or OpCode.OpConstantFalse or OpCode.OpConstantNull or OpCode.OpConstantComposite or OpCode.OpUndef;\nif (!IsCompileTimeConstant(instruction)) throw new NotSupportedException($\"Non-constant opcode {instruction.Op} in constant context\");","typeGuard":"static bool IsConstantOp(OpData i) => i.Op is OpCode.OpConstant or OpCode.OpConstantComposite;","tryCatchPattern":null,"preventionTips":["Only pass literal/composite expressions into constant contexts (array sizes, offsets)","Validate shader source constants in SDSL before SPIR-V emission","Log the offending opcode early in custom emitter code"],"tags":["shader","spirv","compilation"],"backgroundTag":"unsupported-operation","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"}