pardeike/Harmony · error · ArgumentException
StructFieldRefAccess<
Error message
StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {instance}, {fieldInfo} caused an exception What it means
Catch-all wrapper in the instance-taking StructFieldRefAccess<T,F>(fieldInfo)(ref instance): any failure during validation or delegate creation/invocation is rethrown as an ArgumentException naming T, F, the instance and the FieldInfo, with the cause as InnerException.
Solutions
- Check ex.InnerException for the actual failure
- Re-validate fieldInfo against typeof(T) and typeof(F) at the call site
- Do not reuse cached field delegates across different struct types
- Pin the expected target assembly version and re-verify FieldInfo after updates
Example fix
// before ref var v = ref AccessTools.StructFieldRefAccess<OtherStruct, int>(fi)(ref instance); // wrong struct type // after ref var v = ref AccessTools.StructFieldRefAccess<MyStruct, int>(fi)(ref instance);
Defensive patterns
Strategy: validation
Validate before calling
if (fi.DeclaringType != typeof(T) || fi.IsStatic || fi.FieldType != typeof(F)) throw new ArgumentException("invalid struct field ref arguments"); Type guard
static bool MatchesStruct<T>(FieldInfo fi) where T : struct => fi.DeclaringType == typeof(T) && !fi.IsStatic && fi.FieldType == typeof(F);
Try / catch
try { ref var v = ref AccessTools.StructFieldRefAccess<T, F>(fi)(ref instance); }
catch (ArgumentException ex) { throw new InvalidOperationException("StructFieldRefAccess failed", ex.InnerException ?? ex); } Prevention
- Never reuse cached struct field delegates across different struct types
- Pin and verify the target assembly version before caching accessors
- Validate FieldInfo once at startup and reuse the validated pair (fi, delegate)
When it happens
Trigger: Same conditions as error 88 (wrong declaring type, static field, F type mismatch) raised from the overload that applies the ref delegate to a specific struct instance.
Common situations: Using a cached delegate built for one struct type against another struct's instance; target library type changed from class to struct (or vice versa) across versions.
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/b3f5718bc76ad507.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/AccessTools.cs:1635
/// <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>.
/// </para>
/// </remarks>
///
public static ref F StructFieldRefAccess<T, F>(ref T instance, FieldInfo fieldInfo) where T : struct
{
if (fieldInfo is null)
throw new ArgumentNullException(nameof(fieldInfo));
try
{
Tools.ValidateStructField<T, F>(fieldInfo);
return ref Tools.StructFieldRefAccess<T, F>(fieldInfo)(ref instance);
}
catch (Exception ex)
{
throw new ArgumentException($"StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {instance}, {fieldInfo} caused an exception", ex);
}
}
/// <summary>A readable/assignable reference delegate to a static field</summary>
/// <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>
/// <returns>A readable/assignable reference to the field</returns>
///
public delegate ref F FieldRef<F>();
/// <summary>Creates a static field reference</summary>
/// <typeparam name="T">The type (can be class or struct) the field is defined in</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,
View on GitHub (pinned to e7872dc170)