pardeike/Harmony · error · Exception
Cannot use with non-ref return type of method
Error message
Cannot use {InjectionType.ResultRef} with non-ref return type {returnType.FullName} of method {original.FullDescription()} What it means
A patch parameter requests a reference to the original method's return value (InjectionType.ResultRef, backed by RefResult<T>). Harmony only supports this when the original method returns by ref (`ref T`); otherwise there is no ref location to hand out, so it throws listing the actual return type.
Solutions
- Use a normal result injection (InjectionType.Result) instead of ResultRef for by-value returns.
- If you need to mutate the result, use a `ref T` parameter pass-through postfix rather than ResultRef.
- Confirm the target signature actually returns `ref T` (check MethodInfo.ReturnType.IsByRef) before registering the patch.
Example fix
// before (target returns int, not ref int)
static void Postfix([HarmonyArgument("resultref")] RefResult<int> resultRef) { ... }
// after
static void Postfix(ref int result) { ... } Defensive patterns
Strategy: validation
Validate before calling
if (usesResultRef && !original.ReturnType.IsByRef)
throw new InvalidOperationException("ResultRef requires a ref-returning method"); Type guard
bool SupportsResultRef(MethodInfo original) => original.ReturnType.IsByRef;
Try / catch
try { harmony.Patch(original, postfix: new HarmonyMethod(fix)); }
catch (Exception ex) when (ex.Message.Contains("with non-ref return type")) { log.Error(ex); } Prevention
- Only use ResultRef for `ref T` methods
- Fall back to Result injection for by-value returns
- Inspect target signature with ildasm/decompiler before patching
When it happens
Trigger: Declaring a ResultRef-injected parameter (RefResult<T>) in a patch targeting a method whose return type is not IsByRef - i.e. any normal by-value return, including `void` and plain `T`.
Common situations: Applying a ref-returning patch to a non-ref overload of the same method name; library update removed `ref` from the target's signature while the patch still assumes it.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Wrong type of for method . Expected , got
- Cannot get result from void method
- Cannot assign method return type
- The type must declare an empty constructor (the constructor…
- position( ) + count( ) > buffer.Length( )
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/90dbc9a0c4b4237b.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCreatorTools.cs:351
if (returnType.IsValueType)
{
if (paramType == typeof(object))
codes.Add(Box[returnType]);
else if (paramType == typeof(object).MakeByRefType())
{
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));
View on GitHub (pinned to e7872dc170)