dotnet/wpf · error · InvalidOperationException
SR.EnumeratorVersionChanged
Error message
SR.EnumeratorVersionChanged
What it means
The JournalEntryStack enumerator snapshots the journal's version when created; VerifyUnchanged (invoked from MoveNext) compares it against the journal's current version. If entries were added, removed, or the journal was navigated between enumerator creation and a MoveNext call, the enumerator is stale and InvalidOperationException (EnumeratorVersionChanged) is thrown, mirroring the classic 'collection was modified' guard.
Solutions
- Materialize the entries into a list (ToList) before navigating, or complete the enumeration before triggering navigation.
- Defer navigation out of the enumeration loop (Dispatcher.BeginInvoke) so mutation happens after MoveNext finishes.
- If deferred enumeration is intended, re-create the enumerator after any journal change instead of continuing to use the stale one.
Example fix
// before
foreach (var entry in journal) // user clicks Back inside loop -> version changes
{
Log(entry);
if (shouldGoBack) navService.GoBack();
}
// after
var snapshot = journal.ToList();
foreach (var entry in snapshot) { Log(entry); }
if (shouldGoBack) navService.GoBack(); Defensive patterns
Strategy: validation
Validate before calling
bool journalUnchanged = journal.Version == enumeratorVersionAtCreation; // snapshot Version before enumerating
Type guard
bool CanEnumerate(Journal j, int capturedVersion) => j.Version == capturedVersion;
Try / catch
try { foreach (var e in journal) Process(e); }
catch (InvalidOperationException) { enumerator = journal.GetEnumerator(); /* restart */ } Prevention
- Snapshot the journal entries with ToList() before performing any navigation
- Never navigate (GoBack/GoForward/Navigate) inside a foreach over journal entries
- Defer navigation via Dispatcher.BeginInvoke until after enumeration completes
When it happens
Trigger: Enumerating a WPF navigation Journal's entry stack with foreach while navigation occurs (GoBack/GoForward/journal entries added or removed) on the same thread before the enumeration completes.
Common situations: UI code iterating back-stack entries while a NavigationService navigation (e.g. triggered by a button click or event handler inside the loop) mutates the journal; diagnostics/logging code walking the history while the user navigates.
Related errors
- InvalidOperationException
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/20560d13eaa04f70.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Navigation/JournalEntryStack.cs:138
}
_current = null;
return false;
}
public object Current
{
get { return _current; }
}
/// <summary>
/// Verifies that the journal has not been changed since this enumerator was created
/// </summary>
protected void VerifyUnchanged()
{
if (_version != _journal.Version)
{
throw new InvalidOperationException(SR.EnumeratorVersionChanged);
}
}
private Journal _journal;
private int _start;
private int _delta;
private int _next;
private JournalEntry _current;
private JournalEntryFilter _filter;
private int _version;
}
internal class LimitedJournalEntryStackEnumerable : IEnumerable, INotifyCollectionChanged
{
internal LimitedJournalEntryStackEnumerable(IEnumerable ieble)
{
_ieble = ieble;
INotifyCollectionChanged ichildnotify = ieble as INotifyCollectionChanged;View on GitHub (pinned to 81131a70a4)