stride3d/stride · error · Exception

SamplerState already defined

Error message

SamplerState {Name} already defined

What it means

Thrown when compiling a SamplerState member whose Name is already present in the symbol table's RootSymbols, i.e. a duplicate sampler state declaration. Each sampler state name must be unique at the shader root level because it becomes a distinct decorated variable.

Solutions

  1. Rename one of the conflicting SamplerState declarations
  2. Remove the redundant sampler if it duplicates an inherited/composed one
  3. Use mixin overriding semantics intentionally instead of re-declaring the same name

Example fix

// before
SamplerState LinearClampSampler; // also declared in inherited shader
SamplerState LinearClampSampler; // duplicate
// after
SamplerState LinearClampSampler;
SamplerState LinearWrapSampler;
Defensive patterns

Strategy: validation

Validate before calling

if (table.RootSymbols.ContainsKey(sampler.Name))
    throw new InvalidOperationException($"SamplerState {sampler.Name} already defined");

Type guard

bool IsUniqueName(string name, SymbolTable t) => !t.RootSymbols.ContainsKey(name);

Try / catch

try { samplerState.Compile(table, shader, compiler); }
catch (Exception ex) { table.AddError(new(info, ex.Message)); }

Prevention

When it happens

Trigger: Declaring two SamplerState members with the same name in one shader; inheriting/mixin-combining shaders that each declare a SamplerState with the same name; a compose mixin bringing in a sampler that clashes with a locally declared one.

Common situations: Mixin composition where a base shader and an added mixin both define e.g. 'LinearClampSampler'; copy-pasted sampler declarations; renaming a shader but leaving a duplicate sampler behind.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/ShaderElements.MethodOrMember.cs:57

    public Symbol? Symbol { get; private set; }

    public override void ProcessSymbol(SymbolTable table, SpirvContext context)
    {
        base.ProcessSymbol(table, context);
        Type = new PointerType(new SamplerType(), Specification.StorageClass.UniformConstant);
        table.DeclaredTypes.TryAdd(Type.ToString(), Type);

        var sid = new SymbolID(Name, SymbolKind.SamplerState);
        Symbol = new Symbol(sid, Type, 0, OwnerType: table.CurrentShader);
        table.CurrentShader!.Variables.Add((Symbol, IsStaged ? Specification.VariableFlagsMask.Stage : Specification.VariableFlagsMask.None));
    }

    public void Compile(SymbolTable table, ShaderClass shader, CompilerUnit compiler)
    {
        (var builder, var context) = compiler;
        var registeredType = context.GetOrRegister(Type);
        if (table.RootSymbols.TryGetValue(Name, out _))
            throw new Exception($"SamplerState {Name} already defined");

        var variableId = context.Bound++;

        // Encode all sampler state fields into a single OpDecorate
        // Defaults match SamplerStateDescription.Default: Linear(21) filter, Clamp(3) addressing, no LOD bias, 16x aniso, Never(1) compare, full LOD range
        int filter = 21; // TextureFilter.Linear = MIN_MAG_MIP_LINEAR
        int addressU = (int)Specification.SamplerTextureAddressModeSDSL.Clamp;
        int addressV = (int)Specification.SamplerTextureAddressModeSDSL.Clamp;
        int addressW = (int)Specification.SamplerTextureAddressModeSDSL.Clamp;
        int mipLODBias = 0; // BitConverter.SingleToInt32Bits(0.0f) == 0
        int maxAnisotropy = 16;
        int comparisonFunc = (int)Specification.SamplerComparisonFuncSDSL.Never;
        int minLOD = BitConverter.SingleToInt32Bits(-float.MaxValue);
        int maxLOD = BitConverter.SingleToInt32Bits(float.MaxValue);
        int borderR = 0, borderG = 0, borderB = 0, borderA = 0; // Black (0,0,0,0)
        foreach (var parameter in Parameters)
        {
            switch (parameter.Name)

View on GitHub (pinned to 96fad776d2)