{"record":{"id":"630cad9a5ca3c59d","repo":"pardeike/Harmony","slug":"fieldrefaccess-typeof-t-typeof-f-for-fieldname-caused-an","errorCode":null,"errorMessage":"FieldRefAccess<{typeof(T)}, {typeof(F)}> for {fieldName} caused an exception","messagePattern":"FieldRefAccess<(.+?), (.+?)> for (.+?) caused an exception","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/AccessTools.cs","lineNumber":1287,"sourceCode":"\t\t/// For backwards compatibility, there is no class constraint on <typeparamref name=\"T\"/>.\r\n\t\t/// Instead, the non-value-type check is done at runtime within the method.\r\n\t\t/// </para>\r\n\t\t/// </remarks>\r\n\t\t///\r\n\t\tpublic static FieldRef<T, F> FieldRefAccess<T, F>(string fieldName)\r\n\t\t{\r\n\t\t\tif (fieldName is null)\r\n\t\t\t\tthrow new ArgumentNullException(nameof(fieldName));\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tvar delegateInstanceType = typeof(T);\r\n\t\t\t\tif (delegateInstanceType.IsValueType)\r\n\t\t\t\t\tthrow new ArgumentException(\"T (FieldRefAccess instance type) must not be a value type\");\r\n\t\t\t\treturn Tools.FieldRefAccess<T, F>(Tools.GetInstanceField(delegateInstanceType, fieldName), needCastclass: false);\r\n\t\t\t}\r\n\t\t\tcatch (Exception ex)\r\n\t\t\t{\r\n\t\t\t\tthrow new ArgumentException($\"FieldRefAccess<{typeof(T)}, {typeof(F)}> for {fieldName} caused an exception\", ex);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/// <summary>Creates an instance field reference for a specific instance of a class</summary>\r\n\t\t/// <typeparam name=\"T\">The class that defines the instance field, or derived class of this type</typeparam>\r\n\t\t/// <typeparam name=\"F\">\r\n\t\t/// 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),\r\n\t\t/// a type that <see cref=\"Type.IsAssignableFrom(Type)\">is assignable from</see> that type; or if the field's type is an enum type,\r\n\t\t/// either that type or the underlying integral type of that enum type\r\n\t\t/// </typeparam>\r\n\t\t/// <param name=\"instance\">The instance</param>\r\n\t\t/// <param name=\"fieldName\">The name of the field</param>\r\n\t\t/// <returns>A readable/assignable reference to the field</returns>\r\n\t\t/// <remarks>\r\n\t\t/// <para>\r\n\t\t/// This method is meant for one-off access to a field's value for a single instance.\r\n\t\t/// If you need to access a field's value for potentially multiple instances, use <see cref=\"FieldRefAccess{T, F}(string)\"/> instead.\r\n\t\t/// <c>FieldRefAccess&lt;T, F&gt;(instance, fieldName)</c> is functionally equivalent to <c>FieldRefAccess&lt;T, F&gt;(fieldName)(instance)</c>.\r","sourceCodeStart":1269,"sourceCodeEnd":1305,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/AccessTools.cs#L1269-L1305","documentation":"This is the wrapping ArgumentException thrown by FieldRefAccess<T,F> when ANY exception occurs inside the method — including the value-type check, field resolution (GetInstanceField), or delegate construction. The original exception is preserved as InnerException. It gives context about which type/field combination failed.","triggerScenarios":"Calling AccessTools.FieldRefAccess<T, F>(type, fieldName) where the inner step fails: T is a value type, the field does not exist, the field type is not F, or the field is inaccessible for ref-returning delegate creation.","commonSituations":"Renamed/obfuscated field names in a game update, field type changed from int to long (F no longer matches), or T bound to a struct.","solutions":["Inspect the InnerException to see the real cause and fix accordingly","Verify the field exists and its type matches F: AccessTools.Field(typeof(T), fieldName)?.FieldType","Ensure T is a class, not a value type; use StaticFieldRefAccess for static fields","Enable Harmony FileLog debug to see which lookup step failed"],"exampleFix":"// before\nvar acc = AccessTools.FieldRefAccess<Player, int>(\"hp\"); // inner: field renamed to health\n// after\nvar acc = AccessTools.FieldRefAccess<Player, int>(\"health\");","handlingStrategy":"try-catch","validationCode":"var fi = AccessTools.Field(typeof(T), fieldName);\nif (fi is null || fi.FieldType != typeof(F)) throw new InvalidOperationException(\"Field missing or type mismatch\");","typeGuard":null,"tryCatchPattern":"try { var acc = AccessTools.FieldRefAccess<T, F>(type, fieldName); }\ncatch (ArgumentException ex) { /* inspect ex.InnerException */ }","preventionTips":["Always check InnerException — it holds the real cause","Confirm field name against the actual target assembly version","Match F exactly to fi.FieldType","Catch ArgumentException at patch-creation time, not at runtime patch application"],"tags":["reflection","harmony","fieldref","wrapping-exception"],"backgroundTag":"invalid-argument-value","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}