{"record":{"id":"1d35089bde3bf860","repo":"dotnet/wpf","slug":"sr-enumeratornotstarted-hostedelements","errorCode":null,"errorMessage":"SR.EnumeratorNotStarted","messagePattern":"SR\\.EnumeratorNotStarted","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs","lineNumber":168,"sourceCode":"        }\n\n        public IInputElement Current\n        {\n            get\n            {\n                // HostedElements must throw exception if Current property is incorrectly accessed\n                if (_textSegments == null)\n                {\n                    // Collection was modified \n                    // IEnumerator.Current is documented to throw this exception\n                    throw new InvalidOperationException(SR.EnumeratorCollectionDisposed);\n                }\n\n                if (_currentPosition == null)\n                {\n                    // Enumerator not started. Call MoveNext to see if we can move ahead\n                    // IEnumerator.Current is documented to throw this exception\n                    throw new InvalidOperationException(SR.EnumeratorNotStarted);\n                }\n\n                IInputElement currentElement = null;\n                switch (_currentPosition.GetPointerContext(LogicalDirection.Forward))\n                {\n                    case TextPointerContext.ElementStart:\n                        Debug.Assert(_currentPosition.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward) is IInputElement);\n                        currentElement = _currentPosition.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward);\n                        break;\n                    case TextPointerContext.EmbeddedElement:\n                        Debug.Assert(_currentPosition.GetAdjacentElement(LogicalDirection.Forward) is IInputElement);\n                        currentElement = (IInputElement)_currentPosition.GetAdjacentElement(LogicalDirection.Forward);\n                        break;\n                    default:\n                        // Throw exception because this function should only be called after MoveNext, and not \n                        // if MoveNext returns false\n                        Debug.Fail(\"Invalid state in HostedElements.cs\");\n                        break;","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs#L150-L186","documentation":"HostedElements' enumerator exposes IEnumerator.Current before enumeration has begun. Per the IEnumerator contract, accessing Current before the first MoveNext() call throws InvalidOperationException with SR.EnumeratorNotStarted. The source shows Current only dereferences _currentPosition when it is non-null; otherwise it throws.","triggerScenarios":"Reading the Current property of a HostedElements enumerator immediately after GetEnumerator() without calling MoveNext() first. Also occurs after a MoveNext() that returned false (enumeration finished), if code keeps reading Current.","commonSituations":"Hand-rolled foreach replacements (explicit MoveNext/Current loops) that read Current before the first MoveNext; copying enumerator state across iterations; code refactored from foreach to manual enumeration that reordered the calls.","solutions":["Call MoveNext() at least once and only read Current when it returns true.","Use a foreach loop over the HostedElements collection instead of manual enumerator handling so the protocol is enforced.","Guard reads of Current with a check that MoveNext has succeeded at least once.","Reset the enumerator (or obtain a new one) if you need to iterate again after it finished."],"exampleFix":"// before\nvar enumerator = hostedElements.GetEnumerator();\nvar first = enumerator.Current; // throws InvalidOperationException\n\n// after\nvar enumerator = hostedElements.GetEnumerator();\nif (enumerator.MoveNext())\n{\n    var first = enumerator.Current;\n}","handlingStrategy":"validation","validationCode":"// Track MoveNext success before reading Current\nbool moved = enumerator.MoveNext();\nif (!moved)\n{\n    return; // nothing to read; Current is not valid\n}\nvar current = enumerator.Current;","typeGuard":null,"tryCatchPattern":"try\n{\n    var current = enumerator.Current;\n}\ncatch (InvalidOperationException)\n{\n    // enumerator not started or exhausted — call MoveNext first\n}","preventionTips":["Prefer foreach over manual MoveNext/Current handling.","Only read Current when MoveNext() returned true.","Never cache Current across enumerator reset or exhaustion.","Re-create the enumerator instead of resetting when re-iterating."],"tags":["wpf","enumerator","invalidoperationexception"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}