pardeike/Harmony · error · ArgumentException
StructFieldRefAccess<
Error message
StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {fieldInfo} caused an exception What it means
Catch-all wrapper in AccessTools.StructFieldRefAccess<T,F>(fieldInfo): after Tools.ValidateStructField<T,F>(fieldInfo) and delegate creation fail for any reason, the exception is rethrown as an ArgumentException naming T, F and the FieldInfo, with the original exception as InnerException.
Solutions
- Confirm fieldInfo.DeclaringType == typeof(T) (or T-reachable) and the field is an instance field
- Make typeof(F) exactly match fieldInfo.FieldType
- Inspect ex.InnerException to see whether validation or emission failed
- Validate with Tools.ValidateStructField-equivalent checks (IsValueType, !IsStatic, FieldType) before calling
Example fix
// before var rf = AccessTools.StructFieldRefAccess<MyStruct, object>(fi); // F mismatch // after var rf = AccessTools.StructFieldRefAccess<MyStruct, int>(fi); // F matches FieldType
Defensive patterns
Strategy: validation
Validate before calling
if (fieldInfo is null) throw new ArgumentNullException(nameof(fieldInfo));
if (fieldInfo.IsStatic) throw new ArgumentException("struct field refs require instance fields");
if (!typeof(T).IsValueType || fieldInfo.DeclaringType != typeof(T)) throw new ArgumentException("fieldInfo must be an instance field declared on struct T");
if (fieldInfo.FieldType != typeof(F)) throw new ArgumentException("F must match the field type"); Type guard
static bool IsValidStructField<T, F>(FieldInfo fi) where T : struct => typeof(T).IsValueType && fi is { IsStatic: false } && fi.DeclaringType == typeof(T) && fi.FieldType == typeof(F); Prevention
- Mirror Tools.ValidateStructField checks at your own boundary
- Only pass FieldInfos resolved directly from typeof(T)
- Declare F as the exact field type, not a boxed-compatible type
When it happens
Trigger: fieldInfo's declaring type is not T (or T not assignable to it), the field is static, fieldInfo.FieldType != typeof(F), or delegate emission fails in Tools.StructFieldRefAccess.
Common situations: Passing a FieldInfo discovered on a derived class while T is the struct base; generic reflection code reusing a FieldInfo across types; F declared as object instead of the exact field type.
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
- StructFieldRefAccess<
- StructFieldRefAccess<
- StructFieldRefAccess<
- T (FieldRefAccess instance type) must not be a value type
- FieldRefAccess< , > for caused an exception
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/ac951837c846ff16.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/AccessTools.cs:1602
/// <remarks>
/// <para>
/// This method is meant for cases where the field has already been obtained, avoiding the field searching cost in
/// e.g. <see cref="StructFieldRefAccess{T, F}(string)"/>.
/// </para>
/// </remarks>
///
public static StructFieldRef<T, F> StructFieldRefAccess<T, F>(FieldInfo fieldInfo) where T : struct
{
if (fieldInfo is null)
throw new ArgumentNullException(nameof(fieldInfo));
try
{
Tools.ValidateStructField<T, F>(fieldInfo);
return Tools.StructFieldRefAccess<T, F>(fieldInfo);
}
catch (Exception ex)
{
throw new ArgumentException($"StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {fieldInfo} caused an exception", ex);
}
}
/// <summary>Creates a field reference for an instance field of a struct</summary>
/// <typeparam name="T">The struct that defines the instance field</typeparam>
/// <typeparam name="F">
/// The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type),
/// a type that <see cref="Type.IsAssignableFrom(Type)">is assignable from</see> that type; or if the field's type is an enum type,
/// either that type or the underlying integral type of that enum type
/// </typeparam>
/// <param name="instance">The instance</param>
/// <param name="fieldInfo">The field</param>
/// <returns>A readable/assignable reference to the field</returns>
/// <remarks>
/// <para>
/// This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained.
/// If you need to access a field's value for potentially multiple instances, use <see cref="StructFieldRefAccess{T, F}(FieldInfo)"/> instead.
/// <c>StructFieldRefAccess<T, F>(ref instance, fieldInfo)</c> is functionally equivalent to <c>StructFieldRefAccess<T, F>(fieldInfo)(ref instance)</c>.
View on GitHub (pinned to e7872dc170)