louthy/language-ext · error · InvalidOperationException

Nil iterator has no head

Error message

Nil iterator has no head

What it means

This InvalidOperationException fires when Head is read on the Nil (empty) case of IteratorAsync<A>. Nil represents the end of an async sequence and has no first element, so the Head property is a hard guard with no meaningful value to return. It indicates the consumer did not check IsNil/emptiness before requesting the head of the sequence.

Solutions

  1. Await IsEmpty before awaiting Head.
  2. Prefer AsEnumerable()/AsAsyncEnumerable enumeration or FoldAsync-style combinators over manual Head/Tail stepping.
  3. Guard: `var head = await it.IsEmpty ? Prelude.None : Prelude.Some(await it.Head);`

Example fix

// before
var head = await it.Head;
// after
var head = await it.IsEmpty ? Prelude.None : Prelude.Some(await it.Head);
Defensive patterns

Strategy: validation

Validate before calling

if (await it.IsEmpty) throw new InvalidOperationException("Cannot take Head of an empty async iterator");
var head = await it.Head;

Type guard

static async ValueTask<Option<A>> TryHead<A>(IteratorAsync<A> it) => await it.IsEmpty ? Prelude.None : Prelude.Some(await it.Head);

Try / catch

try { head = await it.Head; }
catch (InvalidOperationException) { head = Option<A>.None; }

Prevention

When it happens

Trigger: Awaiting `.Head` on an IteratorAsync<A> in the Nil state — e.g. after consuming all elements via repeated Tail, or on the Default/Nil singleton.

Common situations: Manual async Head/Tail recursion that doesn't stop at the empty case; awaiting Head on a stream that produced zero elements (e.g. empty DB result); porting sync Iterator code that already guarded but the async port doesn't.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15). Data as JSON: /api/errors/bcad5e355649944c. Report an issue: GitHub.

Appendix: source

Thrown at LanguageExt.Core/Immutable Collections/IteratorAsync/DSL/IteratorAsync.Nil.cs:22

namespace LanguageExt;

public abstract partial class IteratorAsync<A>
{
    /// <summary>
    /// Nil iterator case
    ///
    /// The end of the sequence.
    /// </summary>
    public sealed class Nil : IteratorAsync<A>
    {
        public static readonly IteratorAsync<A> Default = new Nil();

        /// <summary>
        /// Head element
        /// </summary>
        public override ValueTask<A> Head =>
            throw new InvalidOperationException("Nil iterator has no head");

        /// <summary>
        /// Tail of the sequence
        /// </summary>
        public override ValueTask<IteratorAsync<A>> Tail =>
            new(this);

        /// <summary>
        /// Return true if there are no elements in the sequence.
        /// </summary>
        public override ValueTask<bool> IsEmpty =>
            new(true);

        /// <summary>
        /// Clone the iterator so that we can consume it without having the head item referenced.
        /// This will stop any GC pressure.
        /// </summary>
        public override IteratorAsync<A> Clone() =>

View on GitHub (pinned to 2f0e362824)