{"record":{"id":"d2d0ecacde049ddf","repo":"pardeike/Harmony","slug":"fieldrefaccess-typeof-f-for-type-fieldname-caused-an","errorCode":null,"errorMessage":"FieldRefAccess<{typeof(F)}> for {type}, {fieldName} caused an exception","messagePattern":"FieldRefAccess<(.+?)> for (.+?), (.+?) caused an exception","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/AccessTools.cs","lineNumber":1381,"sourceCode":"\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tvar fieldInfo = Field(type, fieldName);\r\n\t\t\t\tif (fieldInfo is null)\r\n\t\t\t\t\tthrow new MissingFieldException(type.Name, fieldName);\r\n\t\t\t\t// Backwards compatibility: This supports static fields, even those defined in structs. For static fields, T is effectively ignored.\r\n\t\t\t\tif (fieldInfo.IsStatic is false && fieldInfo.DeclaringType is Type declaringType)\r\n\t\t\t\t{\r\n\t\t\t\t\t// When fieldInfo is passed to FieldRefAccess methods, the T generic class constraint is insufficient to ensure that\r\n\t\t\t\t\t// the field is not a struct instance field, since T could be object, ValueType, or an interface that the struct implements.\r\n\t\t\t\t\tif (declaringType.IsValueType)\r\n\t\t\t\t\t\tthrow new ArgumentException(\"Either FieldDeclaringType must be a class or field must be static\");\r\n\t\t\t\t}\r\n\t\t\t\t// Field's declaring type cannot be object, since object has no fields, so always need a castclass for T=object.\r\n\t\t\t\treturn Tools.FieldRefAccess<object, F>(fieldInfo, needCastclass: true);\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(F)}> for {type}, {fieldName} caused an exception\", ex);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/// <summary>Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct)</summary>\r\n\t\t/// <typeparam name=\"F\"> type of the field</typeparam>\r\n\t\t/// <param name=\"typeColonName\">The member in the form <c>TypeFullName:MemberName</c>, where TypeFullName matches the form recognized by <a href=\"https://docs.microsoft.com/en-us/dotnet/api/system.type.gettype\">Type.GetType</a> like <c>Some.Namespace.Type</c>.</param>\r\n\t\t/// <returns>A readable/assignable <see cref=\"FieldRef{T,F}\"/> delegate with <c>T=object</c></returns>\r\n\t\t///\r\n\t\tpublic static FieldRef<object, F> FieldRefAccess<F>(string typeColonName)\r\n\t\t{\r\n\t\t\tvar info = Tools.TypColonName(typeColonName);\r\n\t\t\treturn FieldRefAccess<F>(info.type, info.name);\r\n\t\t}\r\n\r\n\t\t/// <summary>Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct)</summary>\r\n\t\t/// <typeparam name=\"T\">\r\n\t\t/// An arbitrary type if the field is static; otherwise the class that defines the field, or a parent class (including <see cref=\"object\"/>),\r\n\t\t/// implemented interface, or derived class of this type (\"<c>instanceOfT is FieldDeclaringType</c>\" must be possible)\r","sourceCodeStart":1363,"sourceCodeEnd":1399,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/AccessTools.cs#L1363-L1399","documentation":"Wrapping ArgumentException from FieldRefAccess<F>(typeColonName / type, fieldName): thrown when any step fails — field lookup returning null, the struct-instance-field check, or delegate creation. InnerException carries the root cause; the message names the type and field for quick identification.","triggerScenarios":"Calling AccessTools.FieldRefAccess<F>(\"Namespace.Type:fieldName\") or FieldRefAccess<F>(type, fieldName) where the field does not exist, is an instance field of a struct, or cannot support a ref-returning delegate.","commonSituations":"Typo in TypeFullName:MemberName string after an assembly update; attempting struct instance field refs; obfuscated field names in shipped game assemblies.","solutions":["Inspect ex.InnerException for the actual failure","Validate with AccessTools.Field(type, fieldName) before building the delegate","Confirm the field is static or declared on a class","Log/echo the exact typeColonName string to catch format or rename issues"],"exampleFix":"// before\nvar acc = AccessTools.FieldRefAccess<int>(\"Game.Enemy:healt\"); // typo\n// after\nvar acc = AccessTools.FieldRefAccess<int>(\"Game.Enemy:health\");","handlingStrategy":"try-catch","validationCode":"var fi = AccessTools.Field(type, fieldName);\nif (fi is null) throw new InvalidOperationException($\"Field {fieldName} not found on {type}\");\nif (fi.IsStatic is false && fi.DeclaringType is Type dt && dt.IsValueType) throw new InvalidOperationException(\"Struct instance field\");","typeGuard":null,"tryCatchPattern":"try { var acc = AccessTools.FieldRefAccess<F>(typeColonName); }\ncatch (ArgumentException ex) { /* inspect ex.InnerException */ }","preventionTips":["Verify the typeColonName string against the target assembly each version bump","Resolve the FieldInfo first, then build the delegate","Log the exact string on failure for fast diagnosis"],"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"}