stride3d/stride · error · ArgumentException

Invalid 'source' IEnumerable.

Error message

Invalid 'source' IEnumerable.

What it means

EnumerableExtensions.IsNullOrEmpty checks whether an IEnumerable is null or has no elements by obtaining its enumerator. If source.GetEnumerator() returns null (legal for a null-returning custom implementation), it throws ArgumentException with the message "Invalid 'source' IEnumerable.". This is a defensive check for broken IEnumerable implementations, not for a null source (which is handled by returning true).

Solutions

  1. Fix the IEnumerable implementation so GetEnumerator() returns a valid non-null IEnumerator (or throw, or return an empty enumerator)
  2. Do not mock with null enumerators; have test stubs return IEnumerator.Empty-style empty enumerators
  3. If you must test suspicious sources, wrap the call in try/catch for ArgumentException
  4. Prefer checking source == null and using Any()/Count with a working collection before relying on IsNullOrEmpty

Example fix

// before
public IEnumerator GetEnumerator() => null; // broken stub
// after
public IEnumerator GetEnumerator() => Array.Empty<object>().GetEnumerator();
Defensive patterns

Strategy: type-guard

Validate before calling

if (source == null) return true;
if (source.GetEnumerator() is null)
    throw new ArgumentException("Source must return a valid enumerator.");

Type guard

static bool IsValidEnumerable(IEnumerable? source) =>
    source == null || source.GetEnumerator() != null;

Try / catch

try
{
    bool empty = enumerable.IsNullOrEmpty();
}
catch (ArgumentException ex) when (ex.Message == "Invalid 'source' IEnumerable.")
{
    // source is a broken IEnumerable: fix or replace the implementation
}

Prevention

When it happens

Trigger: Passing an IEnumerable whose GetEnumerator() method returns null — e.g. a mis-implemented custom collection, a stub/mock returning null, or an exotic enumerable wrapper that yields no enumerator.

Common situations: Mocking IEnumerable in unit tests with a stub whose GetEnumerator returns null; custom lazy/streaming collections that fail to produce an enumerator; calling IsNullOrEmpty on a structurally broken third-party collection.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/8648cae7f53a0729. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core/Extensions/EnumerableExtensions.cs:22

using System.Collections;
using System.Diagnostics.Contracts;

namespace Stride.Core.Extensions;

public static class EnumerableExtensions
{
    /// <summary>
    /// Tells whether a sequence is null or empty.
    /// </summary>
    /// <param name="source">The source sequence.</param>
    /// <returns>Returns true if the sequence is null or empty, false if it is not null and contains at least one element.</returns>
    [Pure]
    public static bool IsNullOrEmpty(this IEnumerable? source)
    {
        if (source == null)
            return true;

        var enumerator = source.GetEnumerator() ?? throw new ArgumentException("Invalid 'source' IEnumerable.");
        return enumerator.MoveNext() == false;
    }

    /// <summary>
    /// Executes an action for each (casted) item of the given enumerable.
    /// </summary>
    /// <typeparam name="T">Type of the item value in the enumerable.</typeparam>
    /// <param name="source">Input enumerable to work on.</param>
    /// <param name="action">Action performed for each item in the enumerable.</param>
    /// <remarks>This extension method do not yield. It acts just like a foreach statement, and performs a cast to a typed enumerable in the middle.</remarks>
    public static void ForEach<T>(this IEnumerable source, Action<T> action)
    {
        source.Cast<T>().ForEach(action);
    }

    /// <summary>
    /// Executes an action for each item of the given enumerable.
    /// </summary>

View on GitHub (pinned to 96fad776d2)