stride3d/stride · error · InvalidOperationException

Cannot find type for composite constant type id

Error message

Cannot find type for composite constant type id {typeId}

What it means

ConstantExpression.ParseInstruction throws this InvalidOperationException when parsing an OpConstantComposite/OpSpecConstantComposite whose result-type id is not present in context.ReverseTypes. Unlike the scalar path (which looks up the type in the buffer), composite parsing needs the parsed SymbolType registered in the context to build a CompositeConstExpr.

Solutions

  1. Use the same SpirvContext that emitted/registered the composite type (check context.ReverseTypes for the typeId before parsing).
  2. Register the composite type in the context (context.GetOrRegister(symbolType)) so ReverseTypes contains the id.
  3. Verify you are not mixing ids from a different buffer/context pair.
  4. For cross-context transfer, parse in the source context first, then Emit into the target context.

Example fix

// before: fresh context can't resolve the composite type
var ctx = new SpirvContext();
var expr = ConstantExpression.ParseFromBuffer(vecConstId, buffer, ctx); // throws
// after: parse with the original context that owns the types
var expr = ConstantExpression.ParseFromBuffer(vecConstId, buffer, originalContext);
Defensive patterns

Strategy: validation

Validate before calling

static bool CompositeTypeRegistered(SpirvContext context, SpirvBuffer buffer, int compositeConstId)
    => buffer.TryGetInstructionById(compositeConstId, out var inst)
       && inst.Op is Op.OpConstantComposite or Op.OpSpecConstantComposite
       && context.ReverseTypes.ContainsKey(inst.Data.Memory.Span[1]);

Try / catch

try
{
    var expr = ConstantExpression.ParseFromBuffer(vecId, buffer, context);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("composite constant type id"))
{
    // parse with the owning context instead, or register the type first
}

Prevention

When it happens

Trigger: Calling ConstantExpression.ParseFromBuffer on a composite constant (vector/array/struct) when the SpirvContext was not the one that emitted the type — e.g. a fresh or partial context whose ReverseTypes map lacks the type id, or parsing a composite extracted from a foreign buffer.

Common situations: Using a newly constructed SpirvContext with a buffer produced by another context; splicing composite constants across buffers; EmitToBuffer round-trips where the composite type was never registered in the temp context; wrong typeId due to buffer mixing.

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/0e1341bc8bfe3fbb. Report an issue: GitHub.

Appendix: source

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

            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:
            {
                var typeId = inst.Data.Memory.Span[1];
                if (!context.ReverseTypes.TryGetValue(typeId, out var compositeType))
                    throw new InvalidOperationException($"Cannot find type for composite constant type id {typeId}");
                var constituents = inst.Data.Memory.Span[3..];
                var components = new ConstantExpression[constituents.Length];
                for (int i = 0; i < constituents.Length; i++)
                    components[i] = ParseFromBuffer(constituents[i], buffer, context);
                return new CompositeConstExpr(compositeType, components);
            }

            case Op.OpSpecConstantOp:
            {
                var op = (Op)inst.Data.Memory.Span[3];
                switch (op)
                {
                    // Conversions (unary)
                    case Op.OpConvertFToS:
                    case Op.OpConvertFToU:
                    case Op.OpConvertSToF:
                    case Op.OpConvertUToF:
                    case Op.OpSNegate:

View on GitHub (pinned to 96fad776d2)