CloakHQ/CloakBrowser · error · ArgumentException

Cannot choose from an empty collection.

Error message

Cannot choose from an empty collection.

What it means

ArgumentException thrown by the generic HumanRandom.Choice<T> when the list is null or has zero elements. A random index cannot be produced from an empty collection.

Source

Thrown at dotnet/src/CloakBrowser/Human/HumanRandom.cs:60

    /// <summary>Random integer from a <see cref="Range"/> (min, max), inclusive.</summary>
    public static int RandIntRange(Range r) => RandInt((int)r.Min, (int)r.Max);

    /// <summary>Return <c>true</c> with the given probability in [0, 1].</summary>
    public static bool Chance(double probability) => Rng.NextDouble() < probability;

    /// <summary>Pick a random character from a non-empty string, like Python's <c>random.choice</c>.</summary>
    public static char Choice(string options)
    {
        if (string.IsNullOrEmpty(options))
            throw new ArgumentException("Cannot choose from an empty string.", nameof(options));
        return options[Rng.Next(options.Length)];
    }

    /// <summary>Pick a random element from a non-empty list, like Python's <c>random.choice</c>.</summary>
    public static T Choice<T>(IReadOnlyList<T> options)
    {
        if (options == null || options.Count == 0)
            throw new ArgumentException("Cannot choose from an empty collection.", nameof(options));
        return options[Rng.Next(options.Count)];
    }

    /// <summary>Block the current thread for <paramref name="ms"/> milliseconds (no-op if &lt;= 0).</summary>
    public static void SleepMs(double ms)
    {
        if (ms > 0)
            Thread.Sleep((int)Math.Round(ms));
    }

    /// <summary>Asynchronously wait for <paramref name="ms"/> milliseconds (no-op if &lt;= 0).</summary>
    public static Task SleepMsAsync(double ms)
    {
        if (ms <= 0)
            return Task.CompletedTask;
        return Task.Delay((int)Math.Round(ms));
    }
}

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Guard with a Count > 0 check (or ?.Count check) before calling Choice
  2. Fix the filter/predicate so it can produce at least one candidate
  3. Provide a sensible default/fallback element when the list is empty

Example fix

// before
var pick = HumanRandom.Choise(candidates);

// after
var pick = candidates is { Count: > 0 } ? HumanRandom.Choice(candidates) : fallback;
Defensive patterns

Strategy: validation

Validate before calling

if (candidates is not { Count: > 0 }) candidates = new List<T> { fallback };

Type guard

static bool IsChoosable<T>(IReadOnlyList<T> l) => l is { Count: > 0 };

Try / catch

catch (ArgumentException e) when (e.Message.Contains("empty collection")) { /* widen filter and retry */ }

Prevention

When it happens

Trigger: Calling HumanRandom.Choice(list) with an empty or null IReadOnlyList, e.g. a filtered list of candidates (links, viewport waypoints, dictionary keys) that matched nothing.

Common situations: Filtering collections by predicate before random selection (no matches), empty config lists, or empty dictionaries passed as option pools.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/cc2f5f056f0a1bf8. Report an issue: GitHub.