pardeike/Harmony · error · Exception

Method has wrong return type (should be assignable to )

Error message

Method {method.FullDescription()} has wrong return type (should be assignable to {typeof(T).FullName})

What it means

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.

Solutions

  1. Change the type argument T so it matches (or is a base/interface of) the helper method's actual return type
  2. Change the helper method's return type to one assignable to T
  3. Make the helper method void if its result is not needed, since void methods skip the check

Example fix

// before
var result = processor.RunMethod<bool>(instance, "Initialize"); // Initialize returns int
// after
var result = processor.RunMethod<int>(instance, "Initialize");
Defensive patterns

Strategy: validation

Validate before calling

var method = AccessTools.Method(patchClassType, helperName);
if (method is not null && method.ReturnType != typeof(void) && !typeof(T).IsAssignableFrom(method.ReturnType))
    throw new InvalidOperationException($"{helperName} returns {method.ReturnType}, not assignable to {typeof(T)}");

Try / catch

try { result = processor.RunMethod<T>(instance, helperName); }
catch (Exception ex) when (ex.Message.Contains("wrong return type")) { /* fix generic arg or log */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15). Data as JSON: /api/errors/de4496578677c2d4. Report an issue: GitHub.

Appendix: source

Thrown at Harmony/Public/PatchClassProcessor.cs:326

				exStr = exStr.Split('\n').Join(line => $"### {line}", "\n");
				FileLog.Log(exStr.Trim());
			}

			if (exception is HarmonyException)
				throw exception; // assume HarmonyException already wraps the actual exception
			throw new HarmonyException($"Patching exception in method {original.FullDescription()}", exception);
		}

		[SuppressMessage("Style", "IDE0300")]
		T RunMethod<S, T>(T defaultIfNotExisting, T defaultIfFailing, Func<T, string> failOnResult = null, params object[] parameters)
		{
			if (auxilaryMethods.TryGetValue(typeof(S), out var method))
			{
				var input = (parameters ?? []).Union(new object[] { instance }).ToArray();
				var actualParameters = AccessTools.ActualParameters(method, input);

				if (method.ReturnType != typeof(void) && typeof(T).IsAssignableFrom(method.ReturnType) is false)
					throw new Exception($"Method {method.FullDescription()} has wrong return type (should be assignable to {typeof(T).FullName})");

				var result = defaultIfFailing;
				try
				{
					if (method.ReturnType == typeof(void))
					{
						_ = method.Invoke(null, actualParameters);
						result = defaultIfNotExisting;
					}
					else
						result = (T)method.Invoke(null, actualParameters);

					if (failOnResult is not null)
					{
						var error = failOnResult(result);
						if (error is not null)
							throw new Exception($"Method {method.FullDescription()} returned an unexpected result: {error}");
					}

View on GitHub (pinned to e7872dc170)