dotnet/wpf · error · InvalidOperationException
SR.Enumerator_NotStarted
Error message
SR.Enumerator_NotStarted
What it means
GeneralTransformCollection.Enumerator.Current throws this InvalidOperationException when accessed before enumeration has started (internal _index is still -1, i.e. MoveNext() has never been called or Reset() was just called). The non-generic IEnumerator.Current contract requires an exception in this state instead of returning an undefined value.
Solutions
- Call MoveNext() at least once and only read Current when it returns true.
- Prefer a foreach loop, which manages MoveNext/Current ordering correctly.
- If using Reset(), re-issue MoveNext() before touching Current.
- Capture the current item as the return of MoveNext-driven iteration into a local variable instead of re-reading Current later.
Example fix
// before
var e = collection.GetEnumerator();
var first = e.Current; // throws: not started
// after
var e = collection.GetEnumerator();
if (e.MoveNext())
{
var first = e.Current;
} Defensive patterns
Strategy: validation
Validate before calling
// only read Current after a successful MoveNext
if (enumerator.MoveNext()) { var current = enumerator.Current; } Type guard
static bool TryGetCurrent<T>(this IEnumerator<T> e, out T current) { if (e.MoveNext()) { current = e.Current; return true; } current = default; return false; } Try / catch
try { var v = enumerator.Current; }
catch (InvalidOperationException) { /* enumerator not started: call MoveNext() first */ } Prevention
- Read Current strictly inside a MoveNext()==true guard.
- Prefer foreach over manual enumerator usage.
- After Reset(), always MoveNext() before reading Current.
- Store the item in a local during iteration instead of re-reading Current later.
When it happens
Trigger: Accessing Current (or the explicit IEnumerator.Current) on a fresh enumerator from GeneralTransformCollection.GetEnumerator() without calling MoveNext() first, or accessing it immediately after calling Reset().
Common situations: Hand-written enumerator loops that read e.Current before the first e.MoveNext(); Reset()-then-Current patterns ported from code that assumed Current returns the first element; generic reflection/serialization helpers that poke at Current unconditionally.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.Enumerator_ReachedEnd
- SR.Enumerator_CollectionChanged
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/34aadaa2bc6e2f25.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GeneralTransformCollection.cs:849
/// <summary>
/// Current element
///
/// The behavior of IEnumerable<T>.Current is undefined
/// before the first MoveNext and after we have walked
/// off the end of the list. However, the IEnumerable.Current
/// contract requires that we throw exceptions
/// </summary>
public GeneralTransform Current
{
get
{
if (_index > -1)
{
return _current;
}
else if (_index == -1)
{
throw new InvalidOperationException(SR.Enumerator_NotStarted);
}
else
{
Debug.Assert(_index == -2, "expected -2, got " + _index + "\n");
throw new InvalidOperationException(SR.Enumerator_ReachedEnd);
}
}
}
#endregion
#region Data
private GeneralTransform _current;
private GeneralTransformCollection _list;
private uint _version;
private int _index;
#endregion
}View on GitHub (pinned to 81131a70a4)