pardeike/Harmony · error · Exception
Postfix patch must have a "void" return type
Error message
Postfix patch {fix} must have a "void" return type What it means
Harmony requires a non-pass-through postfix to return void (or to be a valid pass-through). When the postfix's return type differs from its first parameter's type (so it is not pass-through) and the return type is not void/continuable, Harmony cannot integrate the return value and throws. This guards against silently ignoring a postfix return value.
Solutions
- Declare the postfix as `static void Postfix(...)`.
- If you intend to modify the result, make it a pass-through: first parameter of type T (receiving the result) and return type exactly T.
- If you intended conditional skipping of the original method, that belongs in a prefix returning bool, not a postfix.
Example fix
// before
static int Postfix(int result) { Log(result); return result + 1; }
// after
static void Postfix(ref int result) { Log(result); result = result + 1; } Defensive patterns
Strategy: validation
Validate before calling
var first = fix.GetParameters().FirstOrDefault();
if (fix.ReturnType != typeof(void) && (first is null || fix.ReturnType != first.ParameterType))
throw new InvalidOperationException($"{fix} must be void or a valid pass-through"); Type guard
bool IsValidPostfix(MethodInfo fix) =>
fix.ReturnType == typeof(void) ||
(fix.GetParameters().FirstOrDefault() is { } p && fix.ReturnType == p.ParameterType); Try / catch
try { processor.Patch(); }
catch (Exception ex) when (ex.Message.Contains("must have a \"void\" return type")) { log.Error(ex); } Prevention
- Default to void postfixes; use `ref T result` to mutate results
- Don't copy prefix signatures into postfixes
- Review patch method return types in code review
When it happens
Trigger: Registering a postfix whose return type is a non-void type that does not match its first parameter's type, e.g. `static bool Postfix()` or `static int Postfix(object result)`, through PatchClassProcessor/CreateReplacement.
Common situations: Writing a postfix that accidentally returns a value (forgot `void`); moving a prefix's body into a postfix while keeping its bool/int return; generic patch methods whose return type doesn't unify with the result parameter.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Prefix patch has not "bool" or "void" return type
- Return type of pass through postfix
- Could not create replacement method
- __state type mismatch in patch
- Cannot assign method return type
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/92977472ad1072ca.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCreator.cs:338
{
config.AddCode(new CodeInstruction(originalIsStatic ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1));
config.AddCode(Ldloc[tmpBoxVar.Key]);
config.AddCode(Unbox_Any[tmpBoxVar.Value]);
config.AddCode(Stobj[tmpBoxVar.Value]);
});
if (fix.ReturnType != typeof(void))
{
var firstFixParam = fix.GetParameters().FirstOrDefault();
var hasPassThroughResultParam = firstFixParam is not null && fix.ReturnType == firstFixParam.ParameterType;
if (hasPassThroughResultParam)
result = true;
else
{
if (firstFixParam is not null)
throw new Exception($"Return type of pass through postfix {fix} does not match type of its first parameter");
throw new Exception($"Postfix patch {fix} must have a \"void\" return type");
}
}
}
return result;
}
internal bool AddFinalizers(bool catchExceptions)
{
var rethrowPossible = true;
var original = config.original;
var originalIsStatic = original.IsStatic;
config.finalizers.Do(fix =>
{
if (catchExceptions)
config.AddCode(this.MarkBlock(ExceptionBlockType.BeginExceptionBlock));
var tmpBoxVars = new List<KeyValuePair<LocalBuilder, Type>>();
config.AddCodes(this.EmitCallParameter(fix, false, out var tmpInstanceBoxingVar, out var tmpObjectVar, out var refResultUsed, tmpBoxVars));
View on GitHub (pinned to e7872dc170)