{"record":{"id":"fe31c5b00bc1f4bc","repo":"dotnet/wpf","slug":"sr-enumerator-notstarted-collectionhelper","errorCode":null,"errorMessage":"SR.Enumerator_NotStarted","messagePattern":"SR\\.Enumerator_NotStarted","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/helpers/CollectionHelper.cs","lineNumber":768,"sourceCode":"                        /// <summary>\n                        /// Current element\n                        ///\n                        /// The behavior of IEnumerable&lt;T>.Current is undefined\n                        /// before the first MoveNext and after we have walked\n                        /// off the end of the list. However, the IEnumerable.Current\n                        /// contract requires that we throw exceptions\n                        /// </summary>\n                        public [[type]] Current\n                        {\n                            get\n                            {\n                                if (_index > -1)\n                                {\n                                    return _current;\n                                }\n                                else if (_index == -1)\n                                {\n                                    throw new InvalidOperationException(SR.Enumerator_NotStarted);\n                                }\n                                else\n                                {\n                                    Debug.Assert(_index == -2, \"expected -2, got \" + _index + \"\\n\");\n                                    throw new InvalidOperationException(SR.Enumerator_ReachedEnd);\n                                }\n                            }\n                        }\n\n                        #endregion\n\n                        #region Data\n                        private [[type]] _current;\n                        private [[resource.Name]] _list;\n                        private uint _version;\n                        private int _index;\n                        #endregion\n                    }","sourceCodeStart":750,"sourceCodeEnd":786,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/helpers/CollectionHelper.cs#L750-L786","documentation":"This InvalidOperationException is thrown by a strongly-typed collection enumerator generated by CollectionHelper (in the WPF mcg codegen tool) when MoveNext() has never been called before accessing Current. The enumerator uses _index == -1 to mean 'before first MoveNext', -2 for 'past the end', and >= 0 for a valid position. The library enforces the IEnumerator contract that Current is only valid between a successful MoveNext() and the next one.","triggerScenarios":"Reading the Current property of the generated collection's enumerator before calling MoveNext() at least once, e.g. `var e = list.GetEnumerator(); var x = e.Current;`.","commonSituations":"Hand-rolled iteration loops that skip the initial MoveNext; code copied from foreach into a manual loop; using Current to 'peek' at the first element; refactoring that moved the MoveNext call after the first Current access.","solutions":["Call MoveNext() and check its return value before accessing Current, or rewrite as a foreach loop which does this automatically.","If you need to inspect the first element, do `if (e.MoveNext()) { var first = e.Current; }`.","Reset the enumerator (or get a new one) if you previously exhausted it and want to iterate again."],"exampleFix":"// before\nvar e = collection.GetEnumerator();\nvar item = e.Current; // throws: not started\n// after\nvar e = collection.GetEnumerator();\nwhile (e.MoveNext())\n{\n    var item = e.Current;\n}","handlingStrategy":"try-catch","validationCode":"if (list == null || list.Count == 0) return; // nothing to read\nvar e = list.GetEnumerator();\nif (!e.MoveNext()) return; // guard before reading Current","typeGuard":"static bool TryFirst<T>(IEnumerator<T> e, out T value) { value = default; if (e == null) return false; if (!e.MoveNext()) return false; value = e.Current; return true; }","tryCatchPattern":"try { var item = enumerator.Current; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"not started\") || ex.Message.Contains(\"NotStarted\")) { /* call MoveNext() first */ }","preventionTips":["Prefer foreach over manual enumerator loops.","Never read Current before a successful MoveNext().","Never reuse an enumerator across iterations without Reset()."],"tags":["enumerator","invalidoperation","wpf-codegen"],"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"}