louthy/language-ext · error · NotSupportedException

must be a Monoid

Error message

{typeof(FAIL).Name} must be a Monoid

What it means

The Alternative instance's Empty for Validation<FAIL> requires FAIL to be a Monoid so it can produce an empty failure value. When MonoidInstance<FAIL> resolves to none, the trait implementation throws NotSupportedException stating the FAIL type must be a Monoid.

Solutions

  1. Provide a Monoid instance for FAIL (implement Monoid<FAIL> with Empty and Append, or derive via traits/deriving)
  2. Use a FAIL type that already has a Monoid (e.g. Seq<string> / Error types with mempty)
  3. Avoid Alternative.Empty for Validation — construct failures with Validation.Fail directly
  4. Register the instance in the trait-collection initialization so MonoidInstance<FAIL>.Instance is Some

Example fix

// before
var e = empty<Validation<Fail>, int>(); // NotSupportedException: Fail must be a Monoid

// after
public struct FailMonoid : Monoid<Fail>
{
    public Fail Empty => Fail.Empty;
    public Fail Append(Fail x, Fail y) => x.Combine(y);
}
// then register/derive so MonoidInstance<Fail> resolves, and call empty<Validation<Fail>, int>()
Defensive patterns

Strategy: validation

Validate before calling

var ok = MonoidInstance<FAIL>.Instance is { IsSome: true };
if (!ok) throw new InvalidOperationException("FAIL must have a Monoid before Alternative.Empty");

Type guard

bool HasMonoid<FAIL>() => MonoidInstance<FAIL>.Instance.IsSome;

Try / catch

try { var e = empty<Validation<FAIL>, A>(); }
catch (NotSupportedException ex) when (ex.Message.EndsWith("must be a Monoid")) { var e = Validation.Fail<FAIL, A>(default!); }

Prevention

When it happens

Trigger: Invoking the Alternative.Empty<A>() member for K<Validation<FAIL>, A> (e.g. via empty()/Prelude.empty or generic Alternative combinators) where FAIL has no registered Monoid instance.

Common situations: Using Validation with a custom FAIL type (e.g. string, custom error record) that lacks a Monoid derivation; calling generic code that requires Alternative.Empty on Validation; upgrading LanguageExt where instance resolution became stricter.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at LanguageExt.Core/Monads/Alternative Monads/Validation/Trait/Validation.TraitImpl.cs:68

        Validation.SuccessI<FAIL, A>(value);

    static K<Validation<FAIL>, B> Applicative<Validation<FAIL>>.Apply<A, B>(
        K<Validation<FAIL>, Func<A, B>> mf,
        K<Validation<FAIL>, A> ma) =>
        mf.ApplyI(ma, SemigroupInstance<FAIL>.Instance);

    static K<Validation<FAIL>, B> Applicative<Validation<FAIL>>.Apply<A, B>(
        K<Validation<FAIL>, Func<A, B>> mf,
        Memo<Validation<FAIL>, A> ma) =>
        mf.ApplyI(ma.Value, SemigroupInstance<FAIL>.Instance);

    static K<Validation<FAIL>, A> Alternative<Validation<FAIL>>.Empty<A>() =>
        MonoidInstance<FAIL>.Instance switch
        {
            { IsSome: true, Value: { } monoid } =>
                Validation.FailI<FAIL, A>(monoid.Empty),

            _ => throw new NotSupportedException($"{typeof(FAIL).Name} must be a Monoid")
        };

    static K<Validation<FAIL>, A> MonoidK<Validation<FAIL>>.Empty<A>() =>
        MonoidInstance<FAIL>.Instance switch
        {
            { IsSome: true, Value: { } monoid } =>
                Validation.FailI<FAIL, A>(monoid.Empty),

            _ => throw new NotSupportedException($"{typeof(FAIL).Name} must be a Monoid")
        };

    static K<Validation<FAIL>, A> SemigroupK<Validation<FAIL>>.Combine<A>(
        K<Validation<FAIL>, A> ma,
        K<Validation<FAIL>, A> mb) =>
        ma.As().CombineFirst(mb.As(), SemigroupInstance<FAIL>.Instance);

    static K<Validation<FAIL>, A> Choice<Validation<FAIL>>.Choose<A>(
        K<Validation<FAIL>, A> ma,

View on GitHub (pinned to 2f0e362824)