louthy/language-ext · error · ArgumentException

Index outside the bounds of the list

Error message

Index outside the bounds of the list

What it means

ListModule.SetItem (the AVL tree worker behind LstInternal.SetItem) throws ArgumentException('Index outside the bounds of the list') when it descends to an empty node while seeking the target index. This is a defensive internal invariant check: the public SetItem normally rejects bad indices first, so reaching it means the index equaled or exceeded the subtree count during recursion.

Solutions

  1. Always go through Lst/LstInternal.SetItem and validate index against the same instance you mutate.
  2. Ensure index is in 0..Count-1 for the exact snapshot being updated.
  3. Avoid calling ListModule.SetItem directly; treat it as internal API.
  4. Audit async workflows so an index computed from one snapshot is never applied to another.

Example fix

// before
var node = ListModule.SetItem(root, value, i); // i may exceed root.Count
// after
if (i < 0 || i >= root.Count) throw new ArgumentOutOfRangeException(nameof(i));
var node = ListModule.SetItem(root, value, i);
Defensive patterns

Strategy: validation

Validate before calling

if (i < 0 || i >= root.Count)
    throw new ArgumentOutOfRangeException(nameof(i));
var node = ListModule.SetItem(root, value, i);

Try / catch

try { var node = ListModule.SetItem(root, value, i); }
catch (ArgumentException ex) when (ex.Message.Contains("Index outside"))
{
    // index did not exist in this tree snapshot
}

Prevention

When it happens

Trigger: SetItem with index >= Root.Count that bypasses the public guard (e.g. a stale Root where the index was valid for an earlier snapshot); direct ListModule.SetItem calls with an out-of-range index; index == node.Left.Count is the only 'replace' position, anything larger falls into the empty-node path.

Common situations: Race-like inconsistencies from mixing list snapshots in async code; custom code invoking ListModule internals; passing indices derived from a different collection.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at LanguageExt.Core/Immutable Collections/List/Internal/Lst.Internal.cs:761

        {
            return Balance(Make(node.Key, Insert(node.Left, key, index), node.Right));
        }
        else
        {
            return Balance(Make(node.Key, node.Left, Insert(node.Right, key, index - node.Left.Count - 1)));
        }
    }

    public static ListItem<A> Add<A>(ListItem<A> node, A key) =>
        node.IsEmpty
            ? new ListItem<A>(1, 1, ListItem<A>.Empty, key, ListItem<A>.Empty)
            : Balance(Make(node.Key, node.Left, Add(node.Right, key)));

    public static ListItem<A> SetItem<A>(ListItem<A> node, A key, int index)
    {
        if (node.IsEmpty)
        {
            throw new ArgumentException("Index outside the bounds of the list");
        }

        if (index == node.Left.Count)
        {
            return new ListItem<A>(node.Height, node.Count, node.Left, key, node.Right);
        }
        else if (index < node.Left.Count)
        {
            return new ListItem<A>(node.Height, node.Count, SetItem(node.Left, key, index), node.Key, node.Right);
        }
        else
        {
            return new ListItem<A>(node.Height, node.Count, node.Left, node.Key, SetItem(node.Right, key, index - node.Left.Count - 1));
        }
    }

    public static T GetItem<T>(ListItem<T> node, int index)
    {

View on GitHub (pinned to 2f0e362824)