louthy/language-ext · error · IndexOutOfRangeException

IndexOutOfRangeException

Error message

IndexOutOfRangeException

What it means

SeqConcat's indexer calls At(index) and throws IndexOutOfRangeException when no underlying segment yields a Some for that index, i.e. the index is negative or past the end of the concatenated sequence.

Solutions

  1. Check 0 <= index && index < seq.Count before indexing
  2. Use seq[index] only inside bounds-checked loops
  3. Use At-style Option access (TryAt) or pattern matching when bounds are uncertain

Example fix

// before
var x = seq[i];
// after
var x = i >= 0 && i < seq.Count ? seq[i] : Option<A>.None;
Defensive patterns

Strategy: type-guard

Validate before calling

bool inBounds = index >= 0 && index < seq.Count;

Type guard

Option<A> TryAt<A>(Seq<A> seq, int i) => i >= 0 && i < seq.Count ? seq[i] : Option<A>.None;

Try / catch

try { x = seq[index]; }
catch (IndexOutOfRangeException)
{ x = fallback; }

Prevention

When it happens

Trigger: Indexing a Seq (backed by SeqConcat) with seq[i] where i >= seq.Count or i < 0.

Common situations: Off-by-one loops using <= Count; assuming a seq is non-empty; caching a Count from an earlier version of the immutable seq after taking/skipping.

Related errors


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

Appendix: source

Thrown at LanguageExt.Core/Immutable Collections/Seq/DSL/SeqConcat.cs:27

namespace LanguageExt;

internal class SeqConcat<A>(Seq<ISeqInternal<A>> ms) : ISeqInternal<A>
{
    internal readonly Seq<ISeqInternal<A>> ms = ms;
    
    int selfHash;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public ReadOnlySpan<A> AsSpan() =>
        Strict().AsSpan();

    public A this[int index]
    {
        get
        {
            var r = At(index);
            if (r.IsSome) return r.Value!;
            throw new IndexOutOfRangeException();
        }
    }

    public Option<A> At(int index)
    {
        if (index < 0) return default;
        var ms1 = ms;
        while (!ms1.IsEmpty)
        {
            var head = ms1.Head.ValueUnsafe() ?? throw new InvalidOperationException();
            var r    = head.At(index);
            if (r.IsSome) return r;
            index -= head.Count;
            ms1 = ms1.Tail;
        }
        return default;
    }

View on GitHub (pinned to 2f0e362824)