stride3d/stride · error · InvalidOperationException

Cannot find type instruction for id

Error message

Cannot find type instruction for id {typeId}

What it means

ConstantExpression.ParseInstruction throws this InvalidOperationException when an OpConstant/OpSpecConstant references a result-type id that does not exist in the SPIR-V buffer being parsed. The parser needs the OpTypeInt/OpTypeFloat instruction to know how to decode the literal; without it, decoding is impossible.

Solutions

  1. Ensure the complete buffer (including all OpType* instructions) is passed to ParseFromBuffer, not a partial extract.
  2. Verify the constantId belongs to the same buffer instance passed as the 'buffer' argument.
  3. Emit the type instruction into the buffer before the constant (e.g. via context.GetOrRegister before compiling the constant).
  4. Check with buffer.TryGetInstructionById(typeId, ...) in a pre-check to fail early with a clearer message.

Example fix

// before: parsing from a stripped buffer
var expr = ConstantExpression.ParseFromBuffer(constId, strippedBuffer, context); // throws
// after: emit the type first so it is present in the buffer
context.GetOrRegister(ScalarType.Int);
var expr = ConstantExpression.ParseFromBuffer(constId, context.GetBuffer(), context);
Defensive patterns

Strategy: validation

Validate before calling

static bool TypeIsPresent(SpirvBuffer buffer, int constantId)
    => buffer.TryGetInstructionById(constantId, out var inst)
       && inst.Op is Op.OpConstant or Op.OpSpecConstant
       && buffer.TryGetInstructionById(inst.Data.Memory.Span[1], out _);

Try / catch

try
{
    var expr = ConstantExpression.ParseFromBuffer(id, buffer, context);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Cannot find type instruction"))
{
    // buffer is incomplete or id belongs to another buffer — re-emit with full types
}

Prevention

When it happens

Trigger: Calling ConstantExpression.ParseFromBuffer with a buffer that is a fragment/extract (e.g. produced by ExtractConstantFromBuffer or EmitToBuffer) where the type-defining instruction was not copied in, or passing an id from a different buffer than the one containing its type declarations.

Common situations: Manually splicing instructions between SPIR-V buffers; truncating a buffer and losing type declarations; mixing ids from two different SpirvBuffer instances; using ParseFromBuffer on output of EmitToBuffer when the type was never emitted into the temp context.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Core/ConstantExpression.cs:129

                        };
                        return new IntConstExpr(val);
                    }
                    else if (typeInst.Op == Op.OpTypeFloat)
                    {
                        var type = new OpTypeFloat(typeInst);
                        double val = type switch
                        {
                            { Width: 16 } => (double)operand.ToLiteral<Half>(),
                            { Width: 32 } => operand.ToLiteral<float>(),
                            { Width: 64 } => operand.ToLiteral<double>(),
                            _ => throw new NotImplementedException($"Unsupported float width {type.Width}"),
                        };
                        return new FloatConstExpr(val);
                    }
                    else
                        throw new NotImplementedException($"Unsupported constant type {typeInst.Op}");
                }
                throw new InvalidOperationException($"Cannot find type instruction for id {typeId}");
            }

            case Op.OpConstantStringSDSL:
            {
                var operand = inst.Data.Get("literalString");
                return new StringConstExpr(operand.ToLiteral<string>());
            }

            case Op.OpGenericParameterSDSL:
            case Op.OpGenericReferenceSDSL:
            {
                var genParam = (OpGenericParameterSDSL)inst;
                return new GenericParamExpr(genParam.Index, genParam.DeclaringClass);
            }

            case Op.OpConstantComposite:
            case Op.OpSpecConstantComposite:
            {

View on GitHub (pinned to 96fad776d2)