Fixed: "error IDE0044: Make field readonly" in a .NET C# Build
error IDE0044: Make field readonly appeared the first time I made the build check code style. The rule is right more often than not: the field was set once and never changed, so the compiler can promise that it never will. Here's what the rule checks, why it was an error rather than a hint, and the fix.
What I Was Doing
In a .NET 10 solution with TreatWarningsAsErrors on and the default .editorconfig from dotnet new editorconfig, I set EnforceCodeStyleInBuild to true in Directory.Build.props, so dotnet build checks the code-style rules as well. The class library had this class:
namespace Dewiride.Inventory.Data;
public class Class1
{
private string _prefix = "INV-";
public required string Name { get; set; }
public string Code => _prefix + Name;
}
What I Expected
The same clean build as a moment before.
What I Got
Restore complete (0.6s)
Dewiride.Inventory.Data net10.0 failed with 1 error(s) (0.1s)
/Users/you/projects/dewiride-inventory-api/src/Dewiride.Inventory.Data/Class1.cs(5,20): error IDE0044: Make field readonly (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0044)
Build failed with 1 error(s) in 0.8s

(5,20) is line 5, column 20: the field _prefix.
What I Checked
What the rule checks. The IDE0044 page: "This style rule concerns specifying the readonly (C#) or ReadOnly (Visual Basic) modifier for private fields that are initialized (either inline or inside of a constructor) but never reassigned." _prefix is private, initialized inline with "INV-", and only read.
The name. The docs call the rule "Add readonly modifier"; the build prints "Make field readonly". Same rule, IDE0044.
Why It Happens
_prefix matches what IDE0044 looks for: a private field, set where it's declared and never assigned again. Three settings together turned that into a failed build:
- The default
.editorconfighasdotnet_style_readonly_field = true:warning, the option behind IDE0044, atwarning. EnforceCodeStyleInBuildmade the build run code-style rules, which it skips by default.TreatWarningsAsErrorsturned the warning into an error.
The code hadn't changed; the build had started looking.
The Fix
Mark the field readonly:
private readonly string _prefix = "INV-";
readonly means the field can be assigned only where it's declared or in a constructor. The compiler then rejects any later assignment, so nobody can change the prefix by accident.
After the Fix
Restore complete (0.5s)
Dewiride.Inventory.Data net10.0 succeeded (0.2s) → src/Dewiride.Inventory.Data/bin/Debug/net10.0/Dewiride.Inventory.Data.dll
Dewiride.Inventory.Api net10.0 succeeded (0.4s) → src/Dewiride.Inventory.Api/bin/Debug/net10.0/Dewiride.Inventory.Api.dll
Build succeeded in 1.2s

If You Disagree with the Rule
The severity lives in .editorconfig, after the colon. To keep the editor hint without failing the build, lower it:
dotnet_style_readonly_field = true:suggestion
suggestion "Violations appear as build messages and as suggestions in the Visual Studio IDE", which doesn't fail a build. Lowering a rule for the whole solution because of one field is rarely right, though; if one field really must stay writable, it'll be because code assigns it, and then the rule doesn't fire.
Common Mistakes
| Mistake | What happens | Do this instead |
|---|---|---|
Adding readonly to a field that a method assigns | error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) | Leave that field writable; IDE0044 doesn't flag fields that are reassigned |
Turning off EnforceCodeStyleInBuild to get rid of the error | Every code-style rule stops running on build | Fix the field |
| Confusing it with IDE0062 or CA rules | Different rules, different fixes | Read the ID in the message |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
error IDE0044: Make field readonly | A private field is set once and never reassigned, and the build checks code style | Add readonly |
IDE0044 shows up only after EnforceCodeStyleInBuild was turned on | The build runs code-style rules only with that setting | Fix the field, or lower the rule's severity in .editorconfig |
error CS0191: A readonly field cannot be assigned to … after adding readonly | Code assigns the field after construction | Remove readonly from that field |
| It's an error, not a warning | TreatWarningsAsErrors is on | Fix the field, as with any warning |
FAQ
Does readonly make the code faster?
That's not the point of the rule; it's about intent. A reader sees at once that the value never changes, and the compiler enforces it.
Why didn't the editor and the build agree before?
Code-style rules show in the editor, but command-line builds skip them by default. EnforceCodeStyleInBuild makes the build agree with the editor.
Conclusion
error IDE0044: Make field readonly points at a private field that's set once and never reassigned. Add readonly to it. It became a build error here because the default .editorconfig sets the rule to warning, EnforceCodeStyleInBuild made the build check it, and TreatWarningsAsErrors turned the warning into an error.
