{"record":{"id":"ac01773458e9ebb5","repo":"louthy/language-ext","slug":"invalidoperationexception-hashableresolver","errorCode":null,"errorMessage":"InvalidOperationException","messagePattern":"InvalidOperationException","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"LanguageExt.Core/Traits/Resolve/HashableResolver.cs","lineNumber":43,"sourceCode":"        var impl = Resolver.Find(source, \"Hashable\");\n        if (impl is null)\n        {\n            ResolutionError = $\"Trait implementation not found for: {typeof(A).Name}\";\n            MakeDefault();\n            return;\n        }\n        \n        var m = Resolver.Method(impl, \"GetHashCode\", source);\n        if (m is null)\n        {\n            ResolutionError = $\"`GetHashCode` method not found for: {typeof(A).Name}\";\n            MakeDefault();\n            return;\n        }\n\n        GetHashCodeMethod    = m;\n        GetHashCodeMethodPtr = m.MethodHandle.GetFunctionPointer();\n        GetHashCodeFunc      = x => (int?)GetHashCodeMethod.Invoke(null, [x]) ?? throw new InvalidOperationException();\n    }\n    \n    static void MakeDefault()\n    {\n        GetHashCodeFunc      = DefaultGetHashCode;\n        GetHashCodeMethod    = GetHashCodeFunc.Method;\n        GetHashCodeMethodPtr = GetHashCodeFunc.Method.MethodHandle.GetFunctionPointer();\n    }\n\n    static int DefaultGetHashCode(A value) =>\n        value is null ? 0 : value.GetHashCode();\n}\n","sourceCodeStart":25,"sourceCodeEnd":56,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Traits/Resolve/HashableResolver.cs#L25-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npublic static int? GetHashCode(A x) => x == null ? null : x.Hash;\n// after\npublic static int GetHashCode(A x) => x?.GetHashCode() ?? 0;","handlingStrategy":"validation","validationCode":"var m = typeof(HashableImpl).GetMethod(\"GetHashCode\", new[] { typeof(A) });\nbool ok = m is { IsStatic: true } && m.ReturnType == typeof(int);","typeGuard":"bool IsValidHashable<A>(MethodInfo? m) => m is { IsStatic: true } && m.ReturnType == typeof(int) && m.GetParameters().Length == 1;","tryCatchPattern":"try { var h = Hashable<A>.Default.GetHashCode(x); }\ncatch (InvalidOperationException ex) { throw new InvalidOperationException(\"Hashable<A>.GetHashCode returned null; fix its signature to static int\", ex); }","preventionTips":["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"],"tags":["reflection","hashing","resolver","languageext"],"backgroundTag":"invalid-argument-value","analyzedSha":"2f0e3628242889774d4141960a35671a0280051f","analyzedAt":"2026-09-15T03:31:55.716Z","contentChangedAt":"2026-09-15T03:31:55.716Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}