stride3d/stride · error · InvalidOperationException
Resource ' ' has slot in but slot was expected (from SDSL…
Error message
Resource '{resourceName}' has slot {slotStart} in {stage} but slot {entry.SlotStart} was expected (from SDSL compiler). Cross-stage slot mismatch is not supported. What it means
When merging resource binding slots across shader stages into a combined binding table, ShaderCompiler.Compile checks that each resource got the same slot the SDSL compiler assigned. If a resource occupies a different slot in one stage than the recorded SlotStart, the merge is aborted with InvalidOperationException because D3D12 requires consistent register slots for a resource across all stages that use it.
Solutions
- Make the resource's register/slot identical in every shader stage that declares it (use explicit register(bN/tN/uN/sN) consistently).
- Recompile all shader stages from the same SDSL source with the same Stride compiler version so slot assignment is uniform.
- Remove hand-written register() or layout qualifiers that override the SDSL compiler's slot assignment.
- If reflection slots come from an external toolchain, re-run it with options that preserve the declared register order (e.g. no auto-binding renumbering).
- Clear the shader/effect cache and rebuild so stale per-stage bindings are not mixed with fresh ones.
Example fix
// before: mismatch across stages
cbuffer PerFrame : register(b0) { float4x4 View; }; // vs
cbuffer PerFrame : register(b2) { float4x4 View; }; // ps -> throws
// after: same slot in all stages
cbuffer PerFrame : register(b0) { float4x4 View; }; // vs and ps Defensive patterns
Strategy: validation
Validate before calling
// pre-validate binding consistency across stages before compiling the effect
var slots = new Dictionary<string, int>();
foreach (var stage in stageBindings)
foreach (var binding in stage.InputBindings)
{
if (slots.TryGetValue(binding.Name, out var existing) && existing != binding.SlotStart)
throw new InvalidOperationException($"Resource '{binding.Name}' bound to slot {binding.SlotStart} in {stage.Stage} but slot {existing} elsewhere. Align register assignments.");
slots[binding.Name] = binding.SlotStart;
} Try / catch
try
{
var result = shaderCompiler.Compile(source, parameters);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Cross-stage slot mismatch"))
{
log.Error($"Binding slot conflict: {ex.Message}. Make the resource's register identical in every stage.");
throw;
} Prevention
- Never override SDSL-assigned slots with hand-written register() directives in one stage only.
- Declare shared resources (cbuffers, textures) once in a shared SDSL mixin and reuse it across stages.
- Compile all stages from the same Stride compiler version; avoid mixing precompiled and fresh shaders.
- Keep reflection toolchain options that preserve declared register order (no automatic renumbering).
- Wipe the shader cache when changing resource declarations so old slot tables cannot linger.
When it happens
Trigger: ShaderCompiler.Compile processes a stage's input binding whose resource name maps to an entry with a different SlotStart than the slot reported by that stage's reflection — e.g. the same named uniform bound to slot 2 in the pixel shader but slot 3 in the vertex shader, or reflection produced by a different toolchain than the SDSL compiler reorders resource registers.
Common situations: Hand-written HLSL/SPIRV mixed with SDSL shaders where explicit register() assignments disagree; shader stages generated or precompiled by different compiler versions; renaming or reordering resources so SDSL-assigned slots no longer match reflected slots; using precompiled shaders built with an older Stride compiler.
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
- An unknown EffectParameterType was found.
- Unsupported execution model
- Unsupported shader stage
- D3D12 shader compilation is not supported on this platform
- Key [ ] must be a registered key
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/13e25c836c1a8191.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/Direct3D/ShaderCompiler.cs:794
// in the process.
// This is a convenience method to avoid unnecessary reference counting, as implicit conversions
// in the ComPtr<T> class will call AddRef() automatically.
//
// NOTE: This is a mirror from the ComPtrHelpers type.
//
static ComPtr<T> ToComPtr<T>(T* comPtr) where T : unmanaged, IComVtbl<T>
{
return new ComPtr<T> { Handle = comPtr };
}
static void UpdateResourceGroupStageFlags(Dictionary<string, (EffectResourceGroupDescription Group, int Index)> index, string resourceName, ShaderStage stage, int slotStart)
{
if (!index.TryGetValue(resourceName, out var loc))
return;
var entry = loc.Group.Entries[loc.Index];
if (entry.SlotStart != slotStart)
throw new InvalidOperationException(
$"Resource '{resourceName}' has slot {slotStart} in {stage} " +
$"but slot {entry.SlotStart} was expected (from SDSL compiler). " +
$"Cross-stage slot mismatch is not supported.");
entry.Stages |= stage.ToFlag();
loc.Group.Entries[loc.Index] = entry;
}
}
}
}
#endif
View on GitHub (pinned to 96fad776d2)