{"record":{"id":"ccc854b12c036633","repo":"louthy/language-ext","slug":"invalid-iterator","errorCode":null,"errorMessage":"Invalid iterator","messagePattern":"Invalid iterator","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"LanguageExt.Core/Effects/IO/IO.cs","lineNumber":545,"sourceCode":"        Schedule schedule,\n        Func<A, bool> predicate)\n    {\n        return go(schedule.PrependZero.Run().GetIterator(), default);\n\n        IO<A> go(Iterator<Duration> iter, A? value) =>\n            iter switch\n            {\n                Iterator<Duration>.Nil =>\n                    IO.pure<A>(value!),\n\n                Iterator<Duration>.Cons(var head, var tail) =>\n                    IO.yieldFor(head)\n                      .Bind(_ => Bracket()\n                               .Bind(v => predicate(v) \n                                              ? IO.pure(v) \n                                              : go(tail, v))),\n                \n                _ => throw new InvalidOperationException(\"Invalid iterator\")\n            };\n    }\n    \n    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    //\n    //  Retrying the effect when it fails\n    //\n\n    /// <summary>\n    /// Retry if the IO computation fails \n    /// </summary>\n    /// <remarks>\n    /// This variant will retry forever\n    /// </remarks>\n    /// <remarks>\n    /// Any resources acquired within a retrying IO computation will automatically be released *if* the operation fails.\n    /// So, successive retries will not grow the acquired resources on each retry iteration.  Any successful operation that\n    /// acquires resources will have them tracked in the usual way. ","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Effects/IO/IO.cs#L527-L563","documentation":"IO.RepeatUntil builds its iteration via an internal enumerable/iterator of IO steps; a switch in the implementation expects a specific head shape (a Cons-like iterator node). If the head is anything else — an empty/terminated iterator or an unexpected IO node — the implementation cannot construct the loop and throws InvalidOperationException(\"Invalid iterator\"). Repeat and RepeatWhile funnel through this code path.","triggerScenarios":"Calling IO.RepeatUntil / Repeat / RepeatWhile with an effect whose internal iteration source yields no steps or a non-standard IO node — typically when the head IO passed to Repeat is not one of the recognized iterator forms the implementation switches on.","commonSituations":"Passing an empty or immediately-completed IO as the looping body; building the repeated effect through custom DSL nodes that the internal switch doesn't recognize; library version changes where iterator representation changed and old constructed nodes no longer match.","solutions":["Ensure the repeated effect is a non-empty, standard IO (e.g. built with IO.pure/IO.lift or plain effects), not an empty/custom iterator node.","Construct the loop with the intended public API: `effect.RepeatUntil(predicate)` on a real effect rather than assembling DSL nodes manually.","If a custom IO node is involved, make it derive from a recognized IO form, or perform your own recursive loop with Bind and a termination check.","Check your LanguageExt version; if you rely on internal iterator shapes, align with the representation in your installed version."],"exampleFix":"// before — feeds an empty/custom iterator node into the repeater\nIO<int> loop = customIteratorNode.RepeatUntil(v => done(v)); // throws\n// after — recursive Bind loop with explicit termination\nIO<int> loop = default(IO<int>);\nloop = IO<int>.lift(() => runStep())\n      .Bind(v => predicate(v) ? IO.pure(v) : go(tail, v));\n// or simply: bodyEffect.RepeatUntil(v => predicate(v)) on a standard IO","handlingStrategy":"validation","validationCode":"static IO<T> requireNonEmpty<T>(IO<T> io, string ctx) =>\n    io is null || io is IOTail<T>\n        ? throw new ArgumentException($\"{ctx}: effect must be a standard non-empty IO\")\n        : io;","typeGuard":"bool isRepeatable<T>(IO<T> io) =>\n    io is not null && io is not IOTail<T> && io is not IO<T>.Empty;","tryCatchPattern":"try { loop = effect.RepeatUntil(p); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Invalid iterator\")\n{\n    loop = runManualLoop(effect, p); // fallback recursive Bind loop\n}","preventionTips":["Only feed standard, non-empty IO effects into Repeat/RepeatUntil/RepeatWhile.","Don't hand-construct DSL iterator nodes for loop bodies; use IO.pure/lift or public combinators.","Pin/verify the LanguageExt version if you depend on internal IO representations.","For unusual loops, write your own recursive Bind with an explicit termination predicate."],"tags":["languageext","io-monad","repeat","iterator","invalid-state"],"backgroundTag":"internal-invariant-violation","analyzedSha":"2f0e3628242889774d4141960a35671a0280051f","analyzedAt":"2026-09-15T03:31:55.716Z","contentChangedAt":"2026-09-15T03:31:55.716Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}