louthy/language-ext · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

Set.FindRange throws ArgumentNullException when keyFrom is null. The set relies on its Ord<A> comparer, which does not accept null keys, so the library validates arguments up front and throws a descriptive ArgumentNullException naming the parameter.

Solutions

  1. Check both bounds for null before calling FindRange
  2. Filter/throw at the source where the keys are produced
  3. Use FindRangeBetween or an Option-based API if available, handling None for missing bounds
  4. try-catch ArgumentNullException at the boundary if nulls are legitimate inputs

Example fix

// before
var range = set.FindRange(fromKey, toKey);
// after
var range = fromKey != null && toKey != null ? set.FindRange(fromKey, toKey) : Iterable.empty<A>();
Defensive patterns

Strategy: validation

Validate before calling

if (keyFrom == null || keyTo == null) return Iterable.empty<A>();
var range = set.FindRange(keyFrom, keyTo);

Type guard

static bool ValidBounds<A>(A from, A to) => from != null && to != null;

Try / catch

try { range = set.FindRange(from, to); }
catch (ArgumentNullException) { range = Iterable.empty<A>(); }

Prevention

When it happens

Trigger: Calling set.FindRange(null, someKey) on a LanguageExt Set.

Common situations: Passing nullable values sourced from user input, config, or DB lookups directly into range queries; missing null handling after deserialization.

Related errors


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

Appendix: source

Thrown at LanguageExt.Core/Immutable Collections/Set/Internal/Set.Internal.cs:266

    /// <summary>
    /// Retrieve the value from exact key, or if not found, the next item 
    /// </summary>
    /// <param name="key">Key to find</param>
    /// <returns>Found key</returns>
    [Pure]
    public Option<A> FindOrSuccessor(A key) => SetModule.TryFindOrSuccessor<OrdA, A>(set, key);

    /// <summary>
    /// Retrieve a range of values 
    /// </summary>
    /// <param name="keyFrom">Range start (inclusive)</param>
    /// <param name="keyTo">Range to (inclusive)</param>
    /// <exception cref="ArgumentNullException">Throws ArgumentNullException the keyFrom or keyTo are null</exception>
    /// <returns>Range of values</returns>
    [Pure]
    public Iterable<A> FindRange(A keyFrom, A keyTo)
    {
        if (isnull(keyFrom)) throw new ArgumentNullException(nameof(keyFrom));
        if (isnull(keyTo)) throw new ArgumentNullException(nameof(keyTo));
        return OrdA.Compare(keyFrom, keyTo) > 0
                   ? SetModule.FindRange<OrdA, A>(set, keyTo, keyFrom).AsIterable()
                   : SetModule.FindRange<OrdA, A>(set, keyFrom, keyTo).AsIterable();
    }


    /// <summary>
    /// Returns the elements that are in both this and other
    /// </summary>
    [Pure]
    public SetInternal<OrdA, A> Intersect(IEnumerable<A> other)
    {
        var root = SetItem<A>.Empty;
        foreach (var item in other)
        {
            if (Contains(item))
            {

View on GitHub (pinned to 2f0e362824)