pardeike/Harmony · error · ApplicationException

The type must declare an empty constructor (the constructor…

Error message

The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).

What it means

FastAccess.CreateInstantiationHandler builds a compiled delegate that calls T's parameterless constructor via IL. Harmony looks up a zero-argument constructor (any visibility) with reflection; if the type declares none, no instantiation delegate can be emitted and this ApplicationException is thrown.

Solutions

  1. Add a parameterless constructor to type T (any accessibility: private, internal, protected, protected internal, or public)
  2. If you cannot modify T, create a dedicated adapter/handler type with an empty constructor
  3. Point the instantiation handler at a different type that has a default constructor
  4. Use Activator.CreateInstance with explicit constructor arguments instead of the fast instantiation handler

Example fix

// before
class Config { public Config(string name) { Name = name; } }
var h = FastAccess.CreateInstantiationHandler<Config>();
// after
class Config { public Config() { } public Config(string name) { Name = name; } }
var h = FastAccess.CreateInstantiationHandler<Config>();
Defensive patterns

Strategy: validation

Validate before calling

var hasDefaultCtor = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) is not null;
if (!hasDefaultCtor) throw new InvalidOperationException($"{typeof(T)} needs a parameterless constructor before CreateInstantiationHandler<T>()");

Type guard

static bool HasEmptyConstructor<T>() => typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) is not null;

Prevention

When it happens

Trigger: Calling CreateInstantiationHandler<T>() (or APIs that use it, e.g. accessing patch/unpatch shared state via AccessTools-created instances) where typeof(T) has no empty constructor — including structs with fields-only, classes with only parameterized constructors, or anonymous types with required args.

Common situations: Using Harmony's AccessTools/FastAccess helpers on a class after adding a constructor with parameters; types defined with required members or primary constructors without a default; plugin authors instantiating config/option classes that only define (string, int) style constructors.

Related errors


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

Appendix: source

Thrown at Harmony/Extras/FastAccess.cs:52

	/// <returns>An delegate</returns>
	///
	public delegate T InstantiationHandler<out T>();

	/// <summary>A helper class for fast access to getters and setters</summary>
	public static class FastAccess
	{
		/// <summary>Creates an instantiation delegate</summary>
		/// <typeparam name="T">Type that constructor creates</typeparam>
		/// <returns>The new instantiation delegate</returns>
		///
		public static InstantiationHandler<T> CreateInstantiationHandler<T>()
		{
			var constructorInfo =
				typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null,
					[], null);
			if (constructorInfo is null)
			{
				throw new ApplicationException(string.Format(
					"The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).",
					typeof(T)));
			}

			var dynamicMethod = new DynamicMethodDefinition($"InstantiateObject_{typeof(T).Name}", typeof(T), null);
			var generator = dynamicMethod.GetILGenerator();
			generator.Emit(OpCodes.Newobj, constructorInfo);
			generator.Emit(OpCodes.Ret);
			return dynamicMethod.Generate().CreateDelegate<InstantiationHandler<T>>();
		}

		/// <summary>Creates an getter delegate for a property</summary>
		/// <typeparam name="T">Type that getter reads property from</typeparam>
		/// <typeparam name="S">Type of the property that gets accessed</typeparam>
		/// <param name="propertyInfo">The property</param>
		/// <returns>The new getter delegate</returns>
		///
		[Obsolete("Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))")]

View on GitHub (pinned to e7872dc170)