OrchardCMS/OrchardCore · error · InvalidOperationException

An uninitialized, or 'default', ValueStopwatch cannot be…

Error message

An uninitialized, or 'default', ValueStopwatch cannot be used to get elapsed time.

What it means

ValueStopwatch is a struct wrapper around Stopwatch.GetTimestamp. A default(ValueStopwatch) has _startTimestamp == 0, meaning it was never started; GetElapsedTime refuses to compute a meaningless elapsed time and throws InvalidOperationException when IsActive is false.

Solutions

  1. Initialize with ValueStopwatch.StartNew() before any GetElapsedTime call.
  2. Check the IsActive property before calling GetElapsedTime and handle the inactive case.
  3. Make the field nullable or wrap it in a class so an uninitialized state is explicit.
  4. Audit failure/early-return paths that skip StartNew but still flow into timing code.

Example fix

// before
private ValueStopwatch _stopwatch;
public void Done() => Log(_stopwatch.GetElapsedTime()); // throws if never started

// after
private ValueStopwatch? _stopwatch;
public void Begin() => _stopwatch = ValueStopwatch.StartNew();
public void Done() { if (_stopwatch is { IsActive: true }) Log(_stopwatch.Value.GetElapsedTime()); }
Defensive patterns

Strategy: type-guard

Validate before calling

if (!stopwatch.IsActive)
    throw new InvalidOperationException("Stopwatch was never started.");

Type guard

bool CanReadElapsed(in ValueStopwatch stopwatch) => stopwatch.IsActive;

Try / catch

try { var elapsed = stopwatch.GetElapsedTime(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("uninitialized"))
{
    _logger.LogWarning("Attempted to read elapsed time from a default ValueStopwatch");
}

Prevention

When it happens

Trigger: Calling GetElapsedTime() on a ValueStopwatch that was never initialized via ValueStopwatch.StartNew() — e.g., an uninitialized field, a struct copied before StartNew, or a default-constructed struct passed into a method.

Common situations: Field declared but StartNew never called on some code path; Stopwatch struct stored in a dictionary and retrieved before insertion; default struct returned from a Try-pattern failure branch.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/b7bfaa0775e8f7cc. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore/Modules/Overrides/HttpClient/ValueStopwatch.cs:27

{
    private readonly long _startTimestamp;

    public readonly bool IsActive => _startTimestamp != 0;

    private ValueStopwatch(long startTimestamp)
    {
        _startTimestamp = startTimestamp;
    }

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

    public TimeSpan GetElapsedTime()
    {
        // Start timestamp can't be zero in an initialized ValueStopwatch. It would have to be literally the first thing executed when the machine boots to be 0.
        // So it being 0 is a clear indication of default(ValueStopwatch).
        if (!IsActive)
        {
            throw new InvalidOperationException("An uninitialized, or 'default', ValueStopwatch cannot be used to get elapsed time.");
        }

        var end = Stopwatch.GetTimestamp();

        return Stopwatch.GetElapsedTime(_startTimestamp, end);
    }
}

View on GitHub (pinned to 4306c0717f)