{"record":{"id":"cc3015d68eaa2fa1","repo":"HangfireIO/Hangfire","slug":"the-type-type-fullname-does-not-contain-a-meth","errorCode":null,"errorMessage":"The type `{type.FullName}` does not contain a method with signature `{key.MethodName}({parametersString})`","messagePattern":"The type `(.+?)` does not contain a method with signature `(.+?)\\((.+?)\\)`","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Storage/InvocationData.cs","lineNumber":350,"sourceCode":"            Func<string, Type> typeResolver, string typeName, string methodName, string parameterTypes,\n            out Type type, out MethodInfo methodInfo)\n        {\n            var entry = MethodDeserializerCache.GetOrAdd(\n                new MethodDeserializerCacheKey { TypeResolver = typeResolver, TypeName = typeName, MethodName = methodName, ParameterTypes = parameterTypes },\n                static key =>\n                {\n                    var type = key.TypeResolver(key.TypeName);\n                    var parameterTypesArray = DeserializeParameterTypesArray(TypeHelper.CurrentTypeSerializer, key.ParameterTypes);\n                    var parameterTypes = parameterTypesArray?.Select(key.TypeResolver).ToArray();\n                    var method = type.GetNonOpenMatchingMethod(key.MethodName, parameterTypes);\n\n                    if (method == null)\n                    {\n                        var parametersString = parameterTypes != null\n                            ? String.Join(\", \", parameterTypes.Select(static x => x.Name))\n                            : key.ParameterTypes ?? String.Empty;\n                    \n                        throw new InvalidOperationException(\n                            $\"The type `{type.FullName}` does not contain a method with signature `{key.MethodName}({parametersString})`\");\n                    }\n\n                    return new MethodDeserializerCacheValue { Type = type, Method = method };\n                });\n\n            type = entry.Type;\n            methodInfo = entry.Method;\n        }\n\n        private static object DeserializeArgument(string argument, Type type)\n        {\n            object value;\n            try\n            {\n                value = SerializationHelper.Deserialize(argument, type, SerializationOption.User);\n            }\n            catch (Exception jsonException) when (jsonException.IsCatchableExceptionType())","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Storage/InvocationData.cs#L332-L368","documentation":"InvalidOperationException thrown inside InvocationData's method-deserializer cache when TypeResolver resolved the type but GetNonOpenMatchingMethod found no method with the stored MethodName and parameter type names. The message prints the expected signature so you can compare it against the current code. Once thrown, the cache entry is not stored, so the resolution is retried on the next attempt.","triggerScenarios":"A persisted job references a method name + parameter types that no longer exist on the resolved type: method renamed, parameter type renamed, method removed, or overload mismatch (e.g. stored parameter is an interface but the method now takes a concrete type).","commonSituations":"Refactoring job methods without deleting queued jobs; changing a parameter from one type to another; splitting a class so the method moved types; version skew between the enqueuing app and the worker app.","solutions":["Read the printed signature from the message and add/restore a method on the resolved type that matches MethodName(parameterTypes) exactly.","Delete the stale job from storage if it can no longer be executed.","Ensure the enqueuing and executing processes reference the same assembly version and method signatures.","Avoid renaming job methods; if you must, ship a forwarding stub during the transition."],"exampleFix":"// before: stored signature ProcessOrder(int) but code now takes Guid\npublic void ProcessOrder(Guid id) { ... }\n\n// after\npublic void ProcessOrder(Guid id) { ... }\npublic void ProcessOrder(int legacyId) => ProcessOrder(Lookup(legacyId));","handlingStrategy":"try-catch","validationCode":"static bool MethodSignatureExists(Type type, string methodName, Type[] parameterTypes)\n    => type.GetMethod(methodName, parameterTypes) != null;","typeGuard":null,"tryCatchPattern":"try\n{\n    invocationData.Deserialize();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"does not contain a method\"))\n{\n    logger.Warn(\"Stale job references missing method; deleting. Detail: {Msg}\", ex.Message);\n    storage.Delete(jobId);\n}","preventionTips":["Run a compatibility check at deploy time that scans queued jobs against current method signatures.","Treat job method signatures as a public contract.","Log the full message (it contains the expected signature) to speed up diagnosis."],"tags":["reflection","method-resolution","compatibility"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}