louthy/language-ext · error · NotSupportedException

Type is not a valid monoid

Error message

Type {typeof(F1).Name} is not a valid monoid

What it means

ValidationT's BiFunctor/Bimonad operations (BiMap) switch on the MonoidInstance registered for the success type F1; if no monoid instance exists for that type, the library cannot combine/discard success values, so it throws NSE. This is a typeclass-lookup failure: the success type of the ValidationT must have a registered Monoid for these operations to work.

Solutions

  1. Implement a Monoid trait instance for the success type F1 so MonoidInstance<F1>.Instance resolves
  2. Use a success type that already has a Monoid registered (e.g. Unit, string, Lst)
  3. Avoid BiMap on ValidationT values whose success type lacks a monoid; restructure so only the failure type is transformed

Example fix

// before
var mapped = ma.BiMap(succ => succ.Count, fail => fail.Message); // NSE: int has no Monoid
// after
[Monoid] // or implement Traits/Monoid<int>
public partial record SuccCount(int Value);
Defensive patterns

Strategy: validation

Validate before calling

if (MonoidInstance<F1>.Instance == null) throw new InvalidOperationException($"{typeof(F1).Name} needs a Monoid before BiMap on ValidationT");

Type guard

bool HasMonoid<F>() => MonoidInstance<F>.Instance is not null;

Try / catch

try { return ma.BiMap(f, g); } catch (NSE ex) { /* fall back to non-bimonad transform or log missing monoid */ }

Prevention

When it happens

Trigger: Calling BiMap on a K<ValidationT<M>, F1, A> where MonoidInstance<F1>.Instance is not registered (F1 is a type with no Monoid trait implementation), and the underlying value is in a Failed state (the Success branch throws NSE separately, otherwise the monoid fallthrough throws).

Common situations: Using ValidationT with a custom success type (e.g. a domain record or int) for which no Monoid instance has been defined, then attempting BiMap/BiTransform-style operations on the outer functor.

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/3e40cbfd888b4654. Report an issue: GitHub.

Appendix: source

Thrown at LanguageExt.Core/Monads/Alternative Monads/ValidationT/Trait/ValidationT.TraitImpl.2.cs:49

        Func<A, B> second,
        K<ValidationT<M>, F1, A> fab) =>
        new ValidationT<F2, M, B>(_ => MonoidInstance<F1>.Instance switch
                                       {
                                           { IsSome: true, Value: { } t } =>
                                               fab.As2()
                                                  .Run(t)
                                                  .Map(v => v switch
                                                            {
                                                                Validation<F1, A>.Fail(var e) =>
                                                                    Validation.FailI<F2, B>(first(e)),

                                                                Validation<F1, A>.Success(var x) =>
                                                                    Validation.SuccessI<F2, B>(second(x)),

                                                                _ => throw new NSE()
                                                            }),

                                           _ => throw new NSE($"Type {typeof(F1).Name} is not a valid monoid")
                                       });

    static K<ValidationT<M>, F2, A> Bimonad<ValidationT<M>>.BindFirst<F1, F2, A>(
        K<ValidationT<M>, F1, A> ma,
        Func<F1, K<ValidationT<M>, F2, A>> f) =>
        new ValidationT<F2, M, A>(ty => MonoidInstance<F1>.Instance switch
                                       {
                                           { IsSome: true, Value: { } tx } =>
                                               ma.As2()
                                                 .Run(tx)
                                                 .Bind(v => v switch
                                                            {
                                                                Validation<F1, A>.Fail (var e) =>
                                                                    f(e).As2().Run(ty),

                                                                Validation<F1, A>.Success (var x) =>
                                                                    M.Pure(Validation.SuccessI<F2, A>(x)),

View on GitHub (pinned to 2f0e362824)