{"record":{"id":"37f14dad752836cc","repo":"pardeike/Harmony","slug":"t-fieldrefaccess-instance-type-must-not-be-a-value-type","errorCode":null,"errorMessage":"T (FieldRefAccess instance type) must not be a value type","messagePattern":"T \\(FieldRefAccess instance type\\) must not be a value type","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/AccessTools.cs","lineNumber":1282,"sourceCode":"\t\t/// </typeparam>\r\n\t\t/// <param name=\"fieldName\">The name of the field</param>\r\n\t\t/// <returns>A readable/assignable <see cref=\"FieldRef{T,F}\"/> delegate</returns>\r\n\t\t/// <remarks>\r\n\t\t/// <para>\r\n\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","sourceCodeStart":1264,"sourceCodeEnd":1300,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/AccessTools.cs#L1264-L1300","documentation":"FieldRefAccess<T,F>(type, fieldName) throws this ArgumentException when T (the instance type used to resolve the field) is a value type, because ref-returning delegates cannot reference fields inside boxed structs. Harmony checks typeof(T).IsValueType before resolving the field and throws immediately. Only class instance types (or a type for static-field compatibility purposes) are supported here.","triggerScenarios":"Calling AccessTools.FieldRefAccess<T, F>(type, fieldName) with T bound to a struct, e.g. FieldRefAccess<MyStruct, int>(...), even if the fieldName identifies a static field.","commonSituations":"Trying to build a fast field-ref delegate for a struct field in a game mod; generic type inference binding T to a value type like Vector3, int, or an enum.","solutions":["Change the type argument T to the class that declares/contains the field; structs are not supported","If the field is static on a struct, use AccessTools.Field or StaticFieldRefAccess<F>(fieldInfo) instead","Use the explicit FieldInfo overload FieldRefAccess<F>(fieldInfo) only for static fields or class-declared instance fields"],"exampleFix":"// before\nvar accessor = AccessTools.FieldRefAccess<MyStruct, int>(\"counter\");\n// after\nvar accessor = AccessTools.StaticFieldRefAccess<int>(AccessTools.Field(typeof(MyStruct), \"counter\"));","handlingStrategy":"validation","validationCode":"if (typeof(T).IsValueType) throw new InvalidOperationException(\"FieldRefAccess requires a class instance type\");\nvar f = AccessTools.Field(typeof(T), fieldName) ?? throw new MissingFieldException(typeof(T).Name, fieldName);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never bind T to a struct; keep the class constraint in mind","Use StaticFieldRefAccess for static fields, including statics on structs","Verify field existence and type before building ref delegates"],"tags":["reflection","harmony","valuetype","fieldref"],"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"}