egametang/ET · error · InvalidOperationException

InvalidOperation_EnumOpCantHappen

Error message

InvalidOperation_EnumOpCantHappen

What it means

Thrown by the non-generic IEnumerator.Current getter when _current is null, i.e. the enumerator has not started (MoveNext never called) or has already finished. Accessing Current outside a valid MoveNext-true window is undefined, so the library rejects it. Surfaces as InvalidOperationException (InvalidOperation_EnumOpCantHappen).

Source

Thrown at Packages/cn.etetet.core/Scripts/Core/Share/Collection/SortedSet.cs:2115

            public T Current
            {
                get
                {
                    if (_current != null)
                    {
                        return _current.Item;
                    }
                    return default(T)!; // Should only happen when accessing Current is undefined behavior
                }
            }

            object IEnumerator.Current
            {
                get
                {
                    if (_current == null)
                    {
                        throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
                    }

                    return _current.Item;
                }
            }

            internal bool NotStartedOrEnded => _current == null;

            internal void Reset()
            {
                if (_version != _tree.version)
                {
                    throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
                }
                _stack.Clear();
                Initialize();
            }

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Always guard Current with a successful MoveNext: if (e.MoveNext()) x = e.Current;
  2. Prefer the generic GetEnumerator()/foreach pattern, which never reads Current prematurely.
  3. Check NotStartedOrEnded (_current == null) before accessing Current in manual code.

Example fix

// before
var e = set.GetEnumerator();
var first = e.Current; // throws

// after
var e = set.GetEnumerator();
object first = e.MoveNext() ? e.Current : null;
Defensive patterns

Strategy: validation

Validate before calling

// Guard Current with a successful MoveNext.
var e = set.GetEnumerator();
T first = e.MoveNext() ? e.Current : default;

Prevention

When it happens

Trigger: Reading IEnumerator.Current before the first MoveNext; reading Current after MoveNext returned false; calling Reset then Current without MoveNext again.

Common situations: Manual enumerator driving (while (e.MoveNext()) ... e.Current) with a logic bug; using the non-generic IEnumerator via LINQ/Reflection that touches Current eagerly; copy-paste of enumerator loops missing the MoveNext guard.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/41bb8f32ea6013d0. Report an issue: GitHub.