stride3d/stride · error · InvalidOperationException

Symbol [ ] could not be found.

Error message

Symbol [{classSource.ClassName}] could not be found.

What it means

Thrown while resolving a shader class source during import: the class name referenced (e.g. a base shader in an inheritance chain) is not present in the ShaderLoader, so its definition cannot be loaded for the inheritance list. Unlike missing symbols within a shader (reported via table.AddError), this is a hard failure.

Solutions

  1. Verify the shader class name spelling and its namespace in the inherit/import clause
  2. Ensure the shader file is in the compiler's asset/search paths so ShaderLoader can find it
  3. Register or load the missing shader class before compiling dependents

Example fix

// before
shader BaseShade : ComputeShader { } // typo: not found
// after
shader BaseShader : ComputeShader { }
Defensive patterns

Strategy: validation

Validate before calling

if (!table.ShaderLoader.Exists(classSource.ClassName))
    throw new InvalidOperationException($"Shader {classSource.ClassName} is not available to the loader");

Type guard

bool ShaderExists(ShaderClassInstantiation c, SymbolTable t) => t.ShaderLoader.Exists(c.ClassName);

Try / catch

try { SpirvBuilder.BuildInheritanceListIncludingSelf(table.ShaderLoader, context, classSource, ...); }
catch (InvalidOperationException ex) { log.Error($"Missing shader class: {ex.Message}"); throw; }

Prevention

When it happens

Trigger: ShaderClassInstantiation whose ClassName is not registered with table.ShaderLoader.Exists; building the inheritance list (BuildInheritanceListIncludingSelf) for a shader that imports or inherits a non-existent shader.

Common situations: Base shader renamed or deleted while derived shaders still reference it; shader not added to the shader compiler's search paths/plugin list; namespace-qualified name mismatch; typo in an 'using'/'inherit' clause.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Literals.cs:647

        if (!table.ResolveExternalTypes)
        {
            var type = new ExternalType(name, generics);
            return new Symbol(new(name, SymbolKind.ExternalType), type, 0);
        }

        // GenericIdentifier is same as Identifier static variable case, except we have generics (which is why GenericIdentifier was chosen over Identifier)
        var compiledGenerics = SDFX.AST.ShaderEffect.CompileGenerics(table, context, generics);
        var classSource = new ShaderClassInstantiation(name, compiledGenerics);
        if (!table.TryResolveSymbol(classSource.ToClassNameWithGenerics(), out var symbol))
        {
            if (!table.ShaderLoader.Exists(name))
            {
                table.AddError(new(info, string.Format(SDSLErrorMessages.SDSL0110, name)));
                return null;
            }

            if (!table.ShaderLoader.Exists(classSource.ClassName))
                throw new InvalidOperationException($"Symbol [{classSource.ClassName}] could not be found.");

            // Shader is inherited (TODO: do we want to do something more "selective", i.e. import only the required variable if it's a cbuffer?)
            var inheritedShaderCount = table.InheritedShaders.Count;
            classSource = SpirvBuilder.BuildInheritanceListIncludingSelf(table.ShaderLoader, context, classSource, table.CurrentMacros.AsSpan(), table.InheritedShaders, ResolveStep.Compile);
            for (int i = inheritedShaderCount; i < table.InheritedShaders.Count; ++i)
            {
                var shaderDefinition = ShaderClass.LoadAndCacheExternalShaderDefinition(table, context, table.InheritedShaders[i]);
                table.InheritedShaders[i].Symbol = shaderDefinition;
                ShaderClass.Inherit(table, context, shaderDefinition, false);
            }

            // We add the typename as a symbol (similar to static access in C#)
            var shaderId = context.GetOrImportShader(classSource.Symbol!);
            symbol = new Symbol(new(classSource.Symbol!.Name, SymbolKind.Shader), new PointerType(new ShaderSymbol(classSource.Symbol.Name, classSource.Symbol.GenericArguments), Specification.StorageClass.Private), shaderId);
            table.CurrentFrame.Add(classSource.ToClassNameWithGenerics(), symbol);
        }

        return symbol;

View on GitHub (pinned to 96fad776d2)