{"record":{"id":"de4496578677c2d4","repo":"pardeike/Harmony","slug":"method-method-fulldescription-has-wrong-return-type-should","errorCode":null,"errorMessage":"Method {method.FullDescription()} has wrong return type (should be assignable to {typeof(T).FullName})","messagePattern":"Method (.+?) has wrong return type \\(should be assignable to (.+?)\\)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Harmony/Public/PatchClassProcessor.cs","lineNumber":326,"sourceCode":"\t\t\t\texStr = exStr.Split('\\n').Join(line => $\"### {line}\", \"\\n\");\r\n\t\t\t\tFileLog.Log(exStr.Trim());\r\n\t\t\t}\r\n\r\n\t\t\tif (exception is HarmonyException)\r\n\t\t\t\tthrow exception; // assume HarmonyException already wraps the actual exception\r\n\t\t\tthrow new HarmonyException($\"Patching exception in method {original.FullDescription()}\", exception);\r\n\t\t}\r\n\r\n\t\t[SuppressMessage(\"Style\", \"IDE0300\")]\r\n\t\tT RunMethod<S, T>(T defaultIfNotExisting, T defaultIfFailing, Func<T, string> failOnResult = null, params object[] parameters)\r\n\t\t{\r\n\t\t\tif (auxilaryMethods.TryGetValue(typeof(S), out var method))\r\n\t\t\t{\r\n\t\t\t\tvar input = (parameters ?? []).Union(new object[] { instance }).ToArray();\r\n\t\t\t\tvar actualParameters = AccessTools.ActualParameters(method, input);\r\n\r\n\t\t\t\tif (method.ReturnType != typeof(void) && typeof(T).IsAssignableFrom(method.ReturnType) is false)\r\n\t\t\t\t\tthrow new Exception($\"Method {method.FullDescription()} has wrong return type (should be assignable to {typeof(T).FullName})\");\r\n\r\n\t\t\t\tvar result = defaultIfFailing;\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tif (method.ReturnType == typeof(void))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t_ = method.Invoke(null, actualParameters);\r\n\t\t\t\t\t\tresult = defaultIfNotExisting;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tresult = (T)method.Invoke(null, actualParameters);\r\n\r\n\t\t\t\t\tif (failOnResult is not null)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar error = failOnResult(result);\r\n\t\t\t\t\t\tif (error is not null)\r\n\t\t\t\t\t\t\tthrow new Exception($\"Method {method.FullDescription()} returned an unexpected result: {error}\");\r\n\t\t\t\t\t}\r","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Public/PatchClassProcessor.cs#L308-L344","documentation":"PatchClassProcessor.RunMethod<T> runs an auxiliary method from a patch class and expects its return value to be assignable to T. If the method returns non-void and its return type is not assignable to T, Harmony throws this Exception before invoking it. It guards the generic invocation from producing an InvalidCastException.","triggerScenarios":"Calling RunMethod<T> (e.g. via PatchClassProcessor helper APIs) with a type argument T where the located auxilary method's ReturnType is neither void nor assignable to typeof(T), such as requesting a bool from a method that returns string or int.","commonSituations":"Developers refactor a patch-class helper method's return type (e.g. void to int or changing a type) and forget to update the generic parameter used at the call site; or copy a RunMethod<T> call between methods with different return types.","solutions":["Change the type argument T so it matches (or is a base/interface of) the helper method's actual return type","Change the helper method's return type to one assignable to T","Make the helper method void if its result is not needed, since void methods skip the check"],"exampleFix":"// before\nvar result = processor.RunMethod<bool>(instance, \"Initialize\"); // Initialize returns int\n// after\nvar result = processor.RunMethod<int>(instance, \"Initialize\");","handlingStrategy":"validation","validationCode":"var method = AccessTools.Method(patchClassType, helperName);\nif (method is not null && method.ReturnType != typeof(void) && !typeof(T).IsAssignableFrom(method.ReturnType))\n    throw new InvalidOperationException($\"{helperName} returns {method.ReturnType}, not assignable to {typeof(T)}\");","typeGuard":null,"tryCatchPattern":"try { result = processor.RunMethod<T>(instance, helperName); }\ncatch (Exception ex) when (ex.Message.Contains(\"wrong return type\")) { /* fix generic arg or log */ }","preventionTips":["Match RunMethod<T>'s T to the helper's declared return type and keep them in sync","Prefer void helper methods when the result is unused","Add a unit test that invokes RunMethod<T> so return-type drift is caught early"],"tags":["csharp","reflection","return-type","harmony"],"backgroundTag":"type-mismatch","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}