Cysharp/UniTask · error · InvalidOperationException

Detected invalid initialization(use 'default'), only to crea

Error message

Detected invalid initialization(use 'default'), only to create from StartNew().

What it means

Thrown by ValueStopwatch.ElapsedTicks when startTimestamp is 0, meaning the stopwatch was created via 'default(ValueStopwatch)' or 'new ValueStopwatch()' instead of ValueStopwatch.StartNew(). ValueStopwatch is a struct; its zero-initialized state is invalid because timestamp 0 is indistinguishable from 'never started'. The IsInvalid property exposes this check.

Source

Thrown at src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/ValueStopwatch.cs:29

        public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());

        ValueStopwatch(long startTimestamp)
        {
            this.startTimestamp = startTimestamp;
        }

        public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks);

        public bool IsInvalid => startTimestamp == 0;

        public long ElapsedTicks
        {
            get
            {
                if (startTimestamp == 0)
                {
                    throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew().");
                }

                var delta = Stopwatch.GetTimestamp() - startTimestamp;
                return (long)(delta * TimestampToTicks);
            }
        }
    }
}

View on GitHub (pinned to ceac8d6946)

Solutions

  1. Always create via ValueStopwatch.StartNew() — never use default or new().
  2. Check sw.IsInvalid before accessing Elapsed if the stopwatch may not have been initialized.
  3. Initialize fields at declaration: private ValueStopwatch sw = ValueStopwatch.StartNew();

Example fix

// before
ValueStopwatch sw;
// ... sw never assigned ...
var elapsed = sw.Elapsed; // throws

// after
var sw = ValueStopwatch.StartNew();
var elapsed = sw.Elapsed; // ok
Defensive patterns

Strategy: validation

Validate before calling

if (stopwatch.IsInvalid)
{
    stopwatch = ValueStopwatch.StartNew();
}
var elapsed = stopwatch.Elapsed;

Type guard

static bool IsStarted(ValueStopwatch sw) => !sw.IsInvalid;

Prevention

When it happens

Trigger: Declaring a ValueStopwatch field or local with default initialization (no assignment) and then accessing .Elapsed or .ElapsedTicks. Using 'new ValueStopwatch()' instead of StartNew(). Forgetting to initialize a stopwatch before first use.

Common situations: A field-level ValueStopwatch that is conditionally started but accessed unconditionally. Copying a stopwatch struct by value after it was zero-initialized. A lazy-initialized field where the access path doesn't check IsInvalid.

Related errors


AI-assisted analysis of Cysharp/UniTask@ceac8d6946 (2026-08-13). Data as JSON: /api/errors/209936d1cdcfaeaf. Report an issue: GitHub.