louthy/language-ext · error · Exception

Eq attribute should have a struct type that derives from…

Error message

Eq attribute should have a struct type that derives from LanguageExt.Traits.Eq<> passed as its argument

What it means

The `[Eq]` attribute on a LanguageExt record declares which type provides equality for the record. Its constructor validates that the supplied `Type` implements `LanguageExt.Traits.Eq<>`; if the passed type doesn't implement that interface, it throws `Exception("Eq attribute should have a struct type that derives from LanguageExt.Traits.Eq<> passed as its argument")` at attribute instantiation time.

Solutions

  1. Make the passed type a struct implementing `LanguageExt.Traits.Eq<TRecord>`: `public readonly struct MyEq : Eq<MyRecord> { ... }`.
  2. If you intended ordering, use `[Ord(typeof(...))]` with an `Ord<T>` implementation instead.
  3. Check the LanguageExt version's trait namespace (`LanguageExt.Traits.Eq<>`) matches your provider's interface.

Example fix

// before
public class MyEq { } // no Eq<T>
[Eq(typeof(MyEq))]
public partial record Person(string Name);

// after
public readonly struct MyEq : Eq<Person>
{
    public bool Equals(Person x, Person y) => x.Name == y.Name;
    public int GetHashCode(Person x) => x.Name?.GetHashCode() ?? 0;
}
[Eq(typeof(MyEq))]
public partial record Person(string Name);
Defensive patterns

Strategy: validation

Validate before calling

bool isValidEqProvider(Type t) =>
    t.IsValueType &&
    t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(LanguageExt.Traits.Eq<>));

Type guard

bool IsValidEqAttributeArg(Type t) =>
    t.GetInterfaces().Any(i => i.ToString().StartsWith("LanguageExt.Traits.Eq`1"));

Try / catch

try { var attr = new EqAttribute(typeof(MyEq)); }
catch (Exception ex) when (ex.Message.StartsWith("Eq attribute should have")) { /* fix the provider type */ }

Prevention

When it happens

Trigger: Annotating a record with `[Eq(typeof(MyEq))]` where `MyEq` does not implement `Eq<T>` (e.g. it implements `IEquatable<T>`, `EqualityComparer<T>`, or `Ord<T>` instead), or passing a non-struct/wrong type. The exception surfaces when the attribute is constructed/reflected over.

Common situations: Migrating from older LanguageExt `Eq`/`Ord` interfaces to `LanguageExt.Traits.Eq<>` without updating attribute types; copy-pasting an `Ord` provider into an `[Eq]` attribute; typos creating a provider with the wrong base interface.

Related errors


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

Appendix: source

Thrown at LanguageExt.Core/DataTypes/Record/Attributes.cs:27

public class NonHashAttribute : Attribute;

public class NonEqAttribute : Attribute;

public class NonOrdAttribute : Attribute;

public class NonShowAttribute : Attribute;

public class EqAttribute : Attribute
{
    public EqAttribute(Type type)
    {
        if (!type.GetTypeInfo()
                 .ImplementedInterfaces
                 .AsIterable()     
                 .Exists(i => i.ToString().StartsWith("LanguageExt.Traits.Eq`1")))
        {
            throw new Exception("Eq attribute should have a struct type that derives from LanguageExt.Traits.Eq<> passed as its argument");
        }
    }
}

public class OrdAttribute : Attribute
{
    public OrdAttribute(Type type)
    {
        if (!type.GetTypeInfo()
                 .ImplementedInterfaces
                 .AsIterable()
                 .Exists(i => i.ToString().StartsWith("LanguageExt.Traits.Ord`1")))
        {
            throw new Exception("Ord attribute should have a struct type that derives from LanguageExt.Traits.Ord<> passed as its argument");
        }
    }
}

View on GitHub (pinned to 2f0e362824)