the symptom, in your words

"A property initializer that reads another property compiles headless but breaks the editor (CS0182)"

✓ verified on 26.07.22
lane Building UIposted

▸ SYMPTOM

  • A C# property initializer that reads another property compiles clean under headless dotnet build, then the editor compile fails with CS0182"an attribute argument must be a constant expression."
  • The error points at a plain property, not at any attribute you wrote.
snippet
public int X { get; init; } = SomeClass.SomeProperty; // green headless, red in editor

▸ CAUSE

The two builds diverge because the editor's code generator embeds property initializers in a position where only compile-time constants are legal. A headless dotnet build never runs that generator, so it accepts a non-constant initializer that the editor later rejects.

The consequence is the familiar trap: a green dotnet build is not proof the editor will accept the same source. This is the same headless-green / editor-red split seen in the razor codegen traps — except here it fires on a plain C# property, not markup.

▸ FIX

Give the property a constant sentinel default and resolve it to the live value at a validation/normalization boundary instead of at declaration time:

snippet
public int X { get; init; } = -1; // -1 = "unset", a compile-time constant

// later, at your validation / normalization step:
if (X == -1)
    X = SomeClass.SomeProperty;

0 or -1 (whatever value can't be a legitimate input) works as the "unset" marker. The declaration now contains only a constant, so the editor's generator is happy, and the real value is filled in where running code — not codegen — can evaluate it.

▸ WHY IT WORKS

The editor and headless builds run different codegen, so "it builds" from the command line can hide an editor-only failure. Defaulting fields to constants and resolving them at a boundary keeps both compilers happy and moves the live lookup to a place where it's actually legal to run.

Verified on engine 26.07.22: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Published.

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord