{"record":{"id":"3b7dfea1d10cea73","repo":"pardeike/Harmony","slug":"cannot-get-result-from-void-method-original-fulldescription","errorCode":null,"errorMessage":"Cannot get result from void method {original.FullDescription()}","messagePattern":"Cannot get result from void method (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Harmony/Internal/MethodCreatorTools.cs","lineNumber":323,"sourceCode":"\t\t\t\t\t\tcodes.Add(paramType.IsByRef ? Ldflda[fieldInfo] : Ldfld[fieldInfo]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (injectionType == InjectionType.State)\r\n\t\t\t\t{\r\n\t\t\t\t\tvar ldlocCode = paramType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc;\r\n\t\t\t\t\tif (config.localVariables.TryGetValue(patch.DeclaringType?.AssemblyQualifiedName ?? \"null\", out var stateVar))\r\n\t\t\t\t\t\tcodes.Add(new CodeInstruction(ldlocCode, stateVar));\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tcodes.Add(Ldnull);\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (injectionType == InjectionType.Result)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (returnType == typeof(void))\r\n\t\t\t\t\t\tthrow new Exception($\"Cannot get result from void method {original.FullDescription()}\");\r\n\t\t\t\t\tvar resultType = paramType;\r\n\t\t\t\t\tif (resultType.IsByRef && returnType.IsByRef is false)\r\n\t\t\t\t\t\tresultType = resultType.GetElementType();\r\n\t\t\t\t\tif (resultType.IsAssignableFrom(returnType) is false)\r\n\t\t\t\t\t\tthrow new Exception($\"Cannot assign method return type {returnType.FullName} to {InjectedParameter.RESULT_VAR} type {resultType.FullName} for method {original.FullDescription()}\");\r\n\t\t\t\t\tvar ldlocCode = paramType.IsByRef && returnType.IsByRef is false ? OpCodes.Ldloca : OpCodes.Ldloc;\r\n\t\t\t\t\tif (returnType.IsValueType && paramType == typeof(object).MakeByRefType())\r\n\t\t\t\t\t\tldlocCode = OpCodes.Ldloc;\r\n\t\t\t\t\tcodes.Add(new CodeInstruction(ldlocCode, config.GetLocal(InjectionType.Result)));\r\n\t\t\t\t\tif (returnType.IsValueType)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (paramType == typeof(object))\r\n\t\t\t\t\t\t\tcodes.Add(Box[returnType]);\r\n\t\t\t\t\t\telse if (paramType == typeof(object).MakeByRefType())\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tcodes.Add(Box[returnType]);\r\n\t\t\t\t\t\t\ttmpObjectVar = config.DeclareLocal(typeof(object));\r\n\t\t\t\t\t\t\tcodes.Add(Stloc[tmpObjectVar]);\r","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Internal/MethodCreatorTools.cs#L305-L341","documentation":"A patch parameter requests the original method's return value (InjectionType.Result, via the RESULT_VAR naming convention such as a `result`/`__result`-style injected parameter). Harmony throws because the original method returns void, so there is no result value to inject. Use the annotation only on methods with a non-void return type.","triggerScenarios":"Annotating/declaring a patch parameter as the result injection (InjectionType.Result) on a patch whose original method has return type void - e.g. patching a `void Process()` method while declaring a result parameter in the patch signature.","commonSituations":"Reusing a generic patch class across methods where some targets are void; refactoring the target method to void while keeping the old patch signature; copy-pasting a postfix between void and non-void targets.","solutions":["Remove the result parameter from the patch signature since the target returns void.","Use a state/local injection or an instance-field/argument injection instead to observe data from a void method.","Split the patch class so void targets use a separate patch method without a result parameter."],"exampleFix":"// before (target: void Save())\nstatic void Postfix([HarmonyArgument(\"result\")] object result) { ... }\n\n// after\nstatic void Postfix() { ... }","handlingStrategy":"validation","validationCode":"if (original.ReturnType == typeof(void) && patchUsesResultInjection(patch))\n    throw new InvalidOperationException(\"Target is void; remove the result parameter\");","typeGuard":"bool ResultUsable(MethodInfo original) => original.ReturnType != typeof(void);","tryCatchPattern":"try { harmony.Patch(original, postfix: new HarmonyMethod(fix)); }\ncatch (Exception ex) when (ex.Message.Contains(\"Cannot get result from void method\")) { log.Error(ex); }","preventionTips":["Check original.ReturnType before writing result parameters","Avoid sharing one patch method across void and non-void targets","Capture state via __state or arguments instead for void methods"],"tags":["harmony","void-method","injection","argument-binding"],"backgroundTag":"invalid-argument-value","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"}