pardeike/Harmony · error · Exception
Wrong type of for method . Expected , got
Error message
Wrong type of {InjectedParameter.RESULT_REF_VAR} for method {original.FullDescription()}. Expected {expectedTypeRef.FullName}, got {resultType.FullName} What it means
The original method returns by ref and ResultRef injection applies, but the injected parameter's type is not exactly `RefResult<T>` (by ref) where T is the target's ref element type. Harmony computes the expected type and throws this Exception when the declared parameter type differs, because the emitted IL (Ldloca of the RefResult local) requires an exact match.
Solutions
- Declare the parameter as `ref RefResult<T>` where T exactly equals the target's ref element type (returnType.GetElementType()).
- Log the expected type from the exception message and align your patch signature with it.
- Add a runtime assertion comparing your parameter type to typeof(RefResult<>).MakeGenericType(target.ReturnType.GetElementType()).MakeByRefType() before patching.
Example fix
// before (target returns ref long)
static void Postfix(RefResult<int> result) { ... }
// after
static void Postfix(ref RefResult<long> result) { ... } Defensive patterns
Strategy: type-guard
Validate before calling
var expected = typeof(RefResult<>).MakeGenericType(original.ReturnType.GetElementType()).MakeByRefType();
if (resultRefParam.ParameterType != expected)
throw new InvalidOperationException($"ResultRef param must be {expected}"); Type guard
bool ResultRefTypeMatches(MethodInfo original, ParameterInfo p) =>
original.ReturnType.IsByRef &&
p.ParameterType == typeof(RefResult<>).MakeGenericType(original.ReturnType.GetElementType()).MakeByRefType(); Try / catch
try { harmony.Patch(original, postfix: new HarmonyMethod(fix)); }
catch (Exception ex) when (ex.Message.Contains("Wrong type of")) { log.Error(ex); } Prevention
- Always declare `ref RefResult<T>` with T = target's ref element type
- Regenerate patch signatures when target element types change
- Add a signature unit test per ref-returning target
When it happens
Trigger: Declaring a ResultRef parameter as RefResult<WrongT>, as a non-generic type, by value instead of by ref, or as a custom wrapper type - while patching a `ref T` method.
Common situations: Target's ref element type changed (ref int -> ref long); writing RefResult<T> without the `ref`/by-ref requirement; patch shared across methods returning different element types.
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
- Cannot assign method return type
- Cannot use with non-ref return type of method
- __state type mismatch in patch
- Return type of pass through postfix
- Cannot get result from void method
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/a9504eda8e492d99.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCreatorTools.cs:357
codes.Add(Box[returnType]);
tmpObjectVar = config.DeclareLocal(typeof(object));
codes.Add(Stloc[tmpObjectVar]);
codes.Add(Ldloca[tmpObjectVar]);
}
}
continue;
}
if (injectionType == InjectionType.ResultRef)
{
if (!returnType.IsByRef)
throw new Exception(
$"Cannot use {InjectionType.ResultRef} with non-ref return type {returnType.FullName} of method {original.FullDescription()}");
var resultType = paramType;
var expectedTypeRef = typeof(RefResult<>).MakeGenericType(returnType.GetElementType()).MakeByRefType();
if (resultType != expectedTypeRef)
throw new Exception(
$"Wrong type of {InjectedParameter.RESULT_REF_VAR} for method {original.FullDescription()}. Expected {expectedTypeRef.FullName}, got {resultType.FullName}");
codes.Add(Ldloca[config.GetLocal(InjectionType.ResultRef)]);
refResultUsed = true;
continue;
}
if (injection.argumentMode != ArgumentMode.Original && config.localVariables.TryGetValue(paramRealName, out var localBuilder))
{
var ldlocCode = paramType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc;
codes.Add(new CodeInstruction(ldlocCode, localBuilder));
continue;
}
int argumentIdx;
if (injection.argumentMode == ArgumentMode.Original)
{
View on GitHub (pinned to e7872dc170)