stride3d/stride · error · InvalidOperationException
Struct not found in shader
Error message
Struct {importStruct.StructName} not found in shader {shaderName} What it means
During SDSL shader mixing, an OpImportStructSDSL instruction imports a struct type declared in another shader referenced via the external shaders context. The mixer looks the struct up in the target shader's own StructTypes and, failing that, in its associated Stage's StructTypes. If the struct is declared in neither, the shader composition is invalid and merging aborts.
Solutions
- Ensure the struct with the exact name exists in the shader being imported from (or in its Stage's StructTypes).
- Fix the struct name in the import statement to match the declaration.
- Check that globalContext.ExternalShaders maps importStruct.Shader to the intended shader.
- Rebuild/clean shader compilation caches after refactoring shader code.
Example fix
// before (shader B imports a struct that no longer exists)
import Struct ShadowParameters from A;
// after (re-add the struct in shader A or correct the name)
struct ShadowParameters { float bias; }; // in shader A
// or: import Struct ShadowParams from A; // matching A's actual struct name Defensive patterns
Strategy: validation
Validate before calling
// Before composing, verify the imported struct exists in the source shader
if (!sourceShader.StructTypes.ContainsKey(importedStructName) &&
(sourceShader.Stage == null || !sourceShader.Stage.StructTypes.ContainsKey(importedStructName)))
throw new InvalidOperationException($"Struct '{importedStructName}' missing in '{shaderName}' before mixing"); Try / catch
// Wrap shader mixing during content/asset build
class ShaderMixException : Exception
{
public ShaderMixException(string shader, string structName, Exception inner)
: base($"Failed to mix '{shader}': missing struct '{structName}'. Check import declarations.", inner) { }
}
try { var result = mixer.Merge(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not found in shader"))
{ throw new ShaderMixException(shaderName, structName, ex); } Prevention
- Keep struct declarations and their imports in sync; search for import sites when renaming a struct.
- Use a shared common shader file for structs imported across multiple shaders.
- Recompile all shaders after refactoring SDSL sources; never mix stale compiled modules.
- Add a unit test that composes every shader class in the project to catch missing imports early.
When it happens
Trigger: ShaderMixer.MergeClassInBuffers encounters an OpImportStructSDSL whose Shader index resolves (via globalContext.ExternalShaders) to a shader that does not declare a struct named importStruct.StructName in ShaderInfo.StructTypes or its Stage.StructTypes.
Common situations: Renaming or deleting a struct in a base shader while dependent shaders still import it; misspelling the struct name in the import; importing from a shader that only declares the struct in a different mixin/stage not attached here; stale compiled shader classes after refactoring SDSL sources.
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
- Could not find compositions for expression
- External variable not found
- Can't find function in current mixin
- Can't find method group info for
- Method was found but a base call can't be performed on a…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/e4a29172c6e3b254.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:616
// Detect when we switch from context to main buffer
if (i2.Op == Op.OpShaderSDSL)
{
isContext = false;
}
// Specific type instructions in context gets deduplicated before adding
bool addToContext = false;
if (TypeDuplicateHelper.OpCheckDuplicateForTypesAndImport(i2.Op))
{
// We need to replace those right now (otherwise further types depending on this struct won't get properly translated)
if (i2.Op == Op.OpImportStructSDSL && new OpImportStructSDSL(ref i2) is { } importStruct)
{
var shaderName = globalContext.ExternalShaders[importStruct.Shader];
var shader2 = mixinNode.ShadersByName[shaderName];
if (!shader2.StructTypes.TryGetValue(importStruct.StructName, out var structId)
&& (shader2.Stage == null || !shader2.Stage.StructTypes.TryGetValue(importStruct.StructName, out structId)))
throw new InvalidOperationException($"Struct {importStruct.StructName} not found in shader {shaderName}");
remapIds.Add(importStruct.ResultId, structId);
removedIds.Add(structId);
}
else
{
// Check if type already exists in context (deduplicate them)
if (typeDuplicateInserter.CheckForDuplicates(i2, out var existingInstruction))
{
if (i2.IdResult is int duplicateId)
{
remapIds.Add(duplicateId, existingInstruction.Data.IdResult!.Value);
var mismatches = typeDuplicateInserter.MergeTypeDecorations(existingInstruction.Data.IdResult.Value, duplicateId);
if (mismatches != null)
{
var details = string.Join("; ", mismatches.Select(m =>
$"{m.Data} (only on {(m.OnKeepOnly ? "kept" : "removed")} type)"));
globalContext.Log.Warning($"Mismatched decorations when merging type {duplicateId} into {existingInstruction.Data.IdResult.Value}: {details}");
foreach (var entry in mismatches)View on GitHub (pinned to 96fad776d2)