How to Resolve Error "CS0591: Invalid value for argument to attribute" in C#
The Compiler Error CS0591 is a restriction error related to Attributes. The message reads: "Invalid value for argument to attribute".
In C#, Attributes (like [Obsolete], [Serializable], or custom attributes) are metadata baked into the compiled Assembly (DLL/EXE). Because they exist in the metadata, their arguments must be fully resolvable at compile-time. This means you can only pass Constant Expressions, typeof() references, or arrays of constants to an attribute. You cannot pass variables, runtime calculations, or objects created with new.
This guide explains what counts as a valid attribute argument and how to fix this error.
Understanding Valid Attribute Arguments
The C# Language Specification restricts attribute arguments to the following types:
- Simple Types:
bool,byte,char,short,int,long,float,double,string. - System Types:
System.Type(using thetypeofoperator). - Enums: Any
enumvalue (provided it is public). - Arrays: Single-dimensional arrays of the types above.
If you try to pass anything else—like a DateTime, a decimal (which is a struct), or a local variable—the compiler raises CS0591.
Scenario 1: Using Variables or Runtime Values
This is the most common mistake. You define a variable and try to pass it into the attribute, thinking the attribute can "read" the variable. It cannot.
Example of error
using System;
[AttributeUsage(AttributeTargets.All)]
public class VersionAttribute : Attribute
{
public VersionAttribute(string version) { }
}
public class Program
{
// A standard variable (calculated at runtime)
static string currentVersion = "1.0." + DateTime.Now.Year;
// ⛔️ Error CS0591: Invalid value for argument to attribute
// The compiler cannot bake a runtime variable into metadata.
[Version(currentVersion)]
public void Run() { }
}
Solution: Use Literals or Constants
You must pass a hardcoded string or a const field.
public class Program
{
// ✅ Correct: 'const' is known at compile-time.
const string FixedVersion = "1.0.2023";
// ✅ Correct: Passing the constant
[Version(FixedVersion)]
public void Run() { }
// ✅ Correct: Passing a literal directly
[Version("2.0.0.0")]
public void RunBeta() { }
}
Scenario 2: Using static readonly instead of const
This is a subtle variation. In C#, static readonly fields are often used as "constants" for objects. However, technically, they are initialized at Runtime (when the class loads). Therefore, they are invalid for attributes.
Example of error
public class Constants
{
// Looks constant, but is initialized at Runtime.
public static readonly int MaxRetries = 5;
}
public class NetworkClient
{
// Custom attribute expecting an int
// ⛔️ Error CS0591: 'Constants.MaxRetries' is not a compile-time constant.
[Retry(Constants.MaxRetries)]
public void Connect() { }
}
Solution: Use const
Change the modifier to const. Note that this only works for primitives and strings.
public class Constants
{
// ✅ Correct: Compile-time constant
public const int MaxRetries = 5;
}
public class NetworkClient
{
[Retry(Constants.MaxRetries)]
public void Connect() { }
}
Scenario 3: Non-Constant Object Instantiation
Unlike Java annotations, C# attributes cannot accept complex objects. Even types like decimal or DateTime are structs that require constructor calls or runtime conversion, making them invalid as attribute arguments.
Example of error
public class PriceAttribute : Attribute
{
public PriceAttribute(decimal amount) { }
}
public class Product
{
// ⛔️ Error CS0591: '10.99m' is a decimal literal.
// In C#, decimals are not primitive constants in metadata;
// they require the 'new Decimal(...)' instruction, which is runtime code.
[Price(10.99m)]
public int Id;
}
Solution: Use Primitive Types
You must change the attribute to accept a primitive type (like double or string) and convert it internally if necessary.
public class PriceAttribute : Attribute
{
public decimal Amount { get; }
// Accept double (primitive) and convert it
public PriceAttribute(double amount)
{
Amount = (decimal)amount;
}
}
public class Product
{
// ✅ Correct: 'double' is a valid attribute argument type.
[Price(10.99)]
public int Id;
}
Types: The typeof(MyClass) expression is valid because Type tokens are stored in metadata. new MyClass() is invalid.
Conclusion
CS0591 enforces the "Metadata Rule": If the compiler can't write the value directly into the DLL header, you can't pass it to an attribute.
- Check Modifiers: Ensure arguments are
const, notstatic readonlyor standard variables. - Check Types: Ensure arguments are primitives (
int,string,bool),enums, ortypeof(). - Avoid Objects: You cannot pass
new Object(),decimal, orDateTimeto an attribute.