louthy/language-ext · error · InvalidOperationException
InvalidOperationException
Error message
InvalidOperationException
What it means
HashableResolver.HashableResolve reflects the Hashable<A> implementation's GetHashCode and wraps it in a delegate. The delegate throws InvalidOperationException when the reflection Invoke yields null where an int was expected — the resolved member doesn't match the required static int GetHashCode(A) contract.
Solutions
- Correct Hashable<A>.GetHashCode to be a static method returning a non-null int.
- Remove the faulty implementation so HashableResolver.MakeDefault (DefaultGetHashCode) is used.
- Handle null A values inside the hash method instead of returning null.
- Confirm the resolved MethodInfo signature before use in tests.
Example fix
// before public static int? GetHashCode(A x) => x == null ? null : x.Hash; // after public static int GetHashCode(A x) => x?.GetHashCode() ?? 0;
Defensive patterns
Strategy: validation
Validate before calling
var m = typeof(HashableImpl).GetMethod("GetHashCode", new[] { typeof(A) });
bool ok = m is { IsStatic: true } && m.ReturnType == typeof(int); Type guard
bool IsValidHashable<A>(MethodInfo? m) => m is { IsStatic: true } && m.ReturnType == typeof(int) && m.GetParameters().Length == 1; Try / catch
try { var h = Hashable<A>.Default.GetHashCode(x); }
catch (InvalidOperationException ex) { throw new InvalidOperationException("Hashable<A>.GetHashCode returned null; fix its signature to static int", ex); } Prevention
- Implement Hashable<A>.GetHashCode as static int GetHashCode(A)
- Handle null A explicitly inside the method body
- Test hashing for null and default values
- Regenerate any code-gen trait implementations after upgrades
When it happens
Trigger: First use of a Hashable<A> instance whose static GetHashCode(A) returns null (or a nullable/boxed value convertible to null) when called through the resolver's GetHashCodeFunc delegate.
Common situations: Custom Hashable implementations with wrong return types; generic type hashing delegates that return null for null arguments; code-gen or source-generation mismatches after upgrades.
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
- InvalidOperationException
- InvalidOperationException
- Ord attribute should have a struct type that derives from…
- Hashable attribute should have a struct type that derives…
- InvalidOperationException
AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15).
Data as JSON: /api/errors/ac01773458e9ebb5.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Traits/Resolve/HashableResolver.cs:43
var impl = Resolver.Find(source, "Hashable");
if (impl is null)
{
ResolutionError = $"Trait implementation not found for: {typeof(A).Name}";
MakeDefault();
return;
}
var m = Resolver.Method(impl, "GetHashCode", source);
if (m is null)
{
ResolutionError = $"`GetHashCode` method not found for: {typeof(A).Name}";
MakeDefault();
return;
}
GetHashCodeMethod = m;
GetHashCodeMethodPtr = m.MethodHandle.GetFunctionPointer();
GetHashCodeFunc = x => (int?)GetHashCodeMethod.Invoke(null, [x]) ?? throw new InvalidOperationException();
}
static void MakeDefault()
{
GetHashCodeFunc = DefaultGetHashCode;
GetHashCodeMethod = GetHashCodeFunc.Method;
GetHashCodeMethodPtr = GetHashCodeFunc.Method.MethodHandle.GetFunctionPointer();
}
static int DefaultGetHashCode(A value) =>
value is null ? 0 : value.GetHashCode();
}
View on GitHub (pinned to 2f0e362824)