stride3d/stride · error · InvalidOperationException

Constant doesn't have a value

Error message

Constant {Name} doesn't have a value

What it means

A field declared with the const TypeModifier must have an initializer. The compiler compiles constants immediately during ProcessSymbol and needs the initializer to produce a constant/spec-constant value, so a const field with Value == null throws this InvalidOperationException.

Solutions

  1. Add an initializer to the const field, e.g. `const float x = 1.0;`.
  2. Remove the const modifier if the value is meant to be assigned at runtime.
  3. For unsized const arrays, supply a full initializer list so the size can be inferred.

Example fix

// before
const float Scale;
// after
const float Scale = 2.0;
Defensive patterns

Strategy: validation

Validate before calling

foreach (var f in shader.Fields)
    if (f.TypeModifier == TypeModifier.Const && f.Value == null)
        throw new InvalidOperationException($"const field {f.Name} needs an initializer");

Try / catch

try { field.ProcessSymbol(table, context); }
catch (InvalidOperationException ex) when (ex.Message.Contains("doesn't have a value"))
{
    // add an initializer or drop the const modifier
}

Prevention

When it happens

Trigger: Declaring `const float x;` (or `static const uint arr[];`) in a shader with no assignment, then compiling the shader.

Common situations: Forward-declaring constants out of C/C++ habit, or a refactoring that removed the initializer expression.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

            var bufTypeName = memberType is AppendStructuredBufferType ? "AppendStructuredBuffer" : "ConsumeStructuredBuffer";
            table.AddError(new(TypeName.Info, $"{bufTypeName} is not supported. Use RWStructuredBuffer with a separate counter buffer instead (variable '{Name}')."));
            return;
        }

        var storageClass = (memberType, StorageClass, StreamKind) switch
        {
            (TextureType or BufferType, _, _) => Specification.StorageClass.UniformConstant,
            (StructuredBufferType or ByteAddressBufferType, _, _) => Specification.StorageClass.StorageBuffer,
            (_, StorageClass.GroupShared, _) => Specification.StorageClass.Workgroup,
            (_, StorageClass.Static, _) => Specification.StorageClass.Private,
            (_, _, StreamKind.Stream or StreamKind.PatchStream) => Specification.StorageClass.Private,
            _ => Specification.StorageClass.Uniform,
        };

        if (TypeModifier == TypeModifier.Const)
        {
            if (Value == null)
                throw new InvalidOperationException($"Constant {Name} doesn't have a value");

            // Constant: compile right away
            var constantValue = Value.CompileConstantValue(table, context, memberType);
            // Infer size for unsized arrays (e.g. `static const uint info[] = {...};`) from
            // the initializer; otherwise indexing the constant later allocates a temp variable
            // typed as runtime array, mismatching the OpSpecConstantComposite's sized OpTypeArray.
            if (memberType is ArrayType { Size: -1 } && Value.ValueType is ArrayType { Size: > 0 } inferred)
                memberType = inferred;
            context.SetName(constantValue.Id, Name);
            var constant = new Symbol(new(Name, SymbolKind.Constant), memberType, constantValue.Id, OwnerType: table.CurrentShader);
            table.CurrentFrame.Add(Name, constant);
            Type = memberType;

            // This constant is visible when inherited (name stored in decoration to avoid dedup conflicts)
            context.Add(new OpDecorateString(constantValue.Id, Specification.Decoration.ShaderConstantSDSL, Name));
        }
        else
        {

View on GitHub (pinned to 96fad776d2)