stride3d/stride · error · InvalidOperationException

Could not find cbuffer member link info for

Error message

Could not find cbuffer member link info for {context.Names[cbuffer.VariableId]}; it should have been generated during MergeCBuffers

What it means

During SPIR-V cbuffer reflection, ShaderMixer.ComputeCBufferReflection requires per-member layout metadata that MergeCBuffers was supposed to record for each composition cbuffer variable. If the dictionary lookup fails, the mixer's internal invariant ('metadata generated during MergeCBuffers') has been violated, so it throws InvalidOperationException naming the cbuffer.

Solutions

  1. Run the standard ShaderMixer.MergeSDSL pipeline end-to-end so MergeCBuffers executes before ComputeCBufferReflection
  2. Check for earlier exceptions or result errors from MergeCBuffers that were ignored, leaving the metadata dictionary incomplete
  3. If using a custom pipeline, replicate the MergeCBuffers step before invoking cbuffer reflection
  4. Update Stride packages to a consistent version so mixer phases match

Example fix

// before: calling reflection without merging
var reflection = mixer.ComputeCBufferReflection(context, cbuffers, cbufferMemberMetadata);
// after: ensure merge phase ran first
var mergeResult = mixer.MergeSDSL(mixinTree, ...); // runs MergeCBuffers internally
if (mergeResult.HasErrors) throw mergeResult.Exceptions.First();
Defensive patterns

Strategy: validation

Validate before calling

if (!mergeResult.HasErrors && cbufferVariableIds.All(id => cbufferMemberMetadata.ContainsKey(id)))
    reflection = mixer.ComputeCBufferReflection(context, cbuffers, cbufferMemberMetadata);

Try / catch

try { reflection = mixer.ComputeCBufferReflection(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("cbuffer member link info")) { logMergePipelineBug(ex); throw; }

Prevention

When it happens

Trigger: Calling ShaderMixer.MergeSDSL on a shader tree where a composition variable's cbuffer member-link metadata was never produced by MergeCBuffers — e.g. a cbuffer variable that survived mixing without passing through the merge step, or a mixer code path/pipeline stage run out of order (reflection executed before the CBuffers merge phase).

Common situations: Custom or forked shader compiler pipelines that invoke ComputeCBufferReflection/ComputeCBufferReflectionData directly instead of going through the full MergeSDSL flow; older or mismatched Stride.Shaders assemblies where MergeCBuffers was skipped due to an earlier exception being swallowed; hand-constructed MixinNode trees.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.CBuffers.cs:446

                // Note: MemberIndexOffset is simply a shift in Members index, not something like a byte offset
                .Select(x => (
                    Variable: x,
                    VariableId: x.Data.IdResult!.Value,
                    StructTypePtrId: x.Data.IdResultType!.Value,
                    StructType: context.ReverseTypes[x.Data.IdResultType.Value] is PointerType p && p.StorageClass == Specification.StorageClass.Uniform && p.BaseType is StructuredType s ? s : null,
                    MemberIndexOffset: 0))
                .Where(x => x.StructType != null)
                .ToList();

            foreach (var cbuffer in cbuffers)
            {
                int constantBufferOffset = 0;
                var cb = cbuffer.StructType!;
                var structTypeId = context.Types[cb];

                var memberInfos = new EffectValueDescription[cb.Members.Count];
                if (!cbufferMemberMetadata.TryGetValue(cbuffer.VariableId, out var cbufferMetadata))
                    throw new InvalidOperationException($"Could not find cbuffer member link info for {context.Names[cbuffer.VariableId]}; it should have been generated during {nameof(MergeCBuffers)}");

                for (var index = 0; index < cb.Members.Count; index++)
                {
                    // Properly compute size and offset according to DirectX rules
                    var member = cb.Members[index];
                    var memberSize = SpirvBuilder.ComputeBufferOffset(member.Type, member.TypeModifier, ref constantBufferOffset, SpirvBuilder.AlignmentRules.CBuffer).Size;

                    DecorateMember(context, structTypeId, index, constantBufferOffset, memberSize, member.Type, member.TypeModifier);

                    var metadata = cbufferMetadata[index];

                    memberInfos[index] = new EffectValueDescription
                    {
                        Type = ConvertType(context, member.Type, member.TypeModifier, SpirvBuilder.AlignmentRules.CBuffer),
                        RawName = member.Name,
                        KeyInfo = new EffectParameterKeyInfo { KeyName = metadata.Link },
                        Offset = constantBufferOffset,
                        Size = memberSize,

View on GitHub (pinned to 96fad776d2)