{"record":{"id":"ffd9a40a4e53c0ef","repo":"pardeike/Harmony","slug":"fielddeclaringtype-must-be-assignable-from-or-to-t","errorCode":null,"errorMessage":"FieldDeclaringType must be assignable from or to T (FieldRefAccess instance type) - \"instanceOfT is FieldDeclaringType\" must be possible","messagePattern":"FieldDeclaringType must be assignable from or to T \\(FieldRefAccess instance type\\) - \"instanceOfT is FieldDeclaringType\" must be possible","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/Tools.cs","lineNumber":134,"sourceCode":"\r\n\t\tinternal static FieldInfo GetInstanceField(Type type, string fieldName)\r\n\t\t{\r\n\t\t\tvar fieldInfo = Field(type, fieldName);\r\n\t\t\tif (fieldInfo is null)\r\n\t\t\t\tthrow new MissingFieldException(type.Name, fieldName);\r\n\t\t\tif (fieldInfo.IsStatic)\r\n\t\t\t\tthrow new ArgumentException(\"Field must not be static\");\r\n\t\t\treturn fieldInfo;\r\n\t\t}\r\n\r\n\t\tinternal static bool FieldRefNeedsClasscast(Type delegateInstanceType, Type declaringType)\r\n\t\t{\r\n\t\t\tvar needCastclass = false;\r\n\t\t\tif (delegateInstanceType != declaringType)\r\n\t\t\t{\r\n\t\t\t\tneedCastclass = delegateInstanceType.IsAssignableFrom(declaringType);\r\n\t\t\t\tif (needCastclass is false && declaringType.IsAssignableFrom(delegateInstanceType) is false)\r\n\t\t\t\t\tthrow new ArgumentException(\"FieldDeclaringType must be assignable from or to T (FieldRefAccess instance type) - \" +\r\n\t\t\t\t\t\t\"\\\"instanceOfT is FieldDeclaringType\\\" must be possible\");\r\n\t\t\t}\r\n\t\t\treturn needCastclass;\r\n\t\t}\r\n\r\n\t\tinternal static void ValidateStructField<T, F>(FieldInfo fieldInfo) where T : struct\r\n\t\t{\r\n\t\t\tif (fieldInfo.IsStatic)\r\n\t\t\t\tthrow new ArgumentException(\"Field must not be static\");\r\n\t\t\tif (fieldInfo.DeclaringType != typeof(T))\r\n\t\t\t\tthrow new ArgumentException(\"FieldDeclaringType must be T (StructFieldRefAccess instance type)\");\r\n\t\t}\r\n\t}\r\n}\r\n","sourceCodeStart":116,"sourceCodeEnd":149,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/Tools.cs#L116-L149","documentation":"FieldRefNeedsClasscast validates that the generic instance type T used with FieldRefAccess can be cast to the field's declaring type (or vice versa). If neither type is assignable to the other, a field ref cannot be formed, so Harmony throws rather than emit invalid castclass IL.","triggerScenarios":"Calling FieldRefAccess<T, F>(fieldInfo) where T (delegateInstanceType) and the field's declaringType are unrelated types (neither IsAssignableFrom the other).","commonSituations":"Using a derived wrapper class as T while the field is declared on a base class the wrapper doesn't inherit; mixing structs/classes; target library refactor moved the field to an unrelated type.","solutions":["Pass T as the field's actual declaring type (or a type in its inheritance chain)","Resolve the fieldInfo with AccessTools.Field(typeof(DeclaringType), \"name\") so declaringType matches T","Check fieldInfo.DeclaringType and your T for mutual assignability before calling"],"exampleFix":"// before\nvar acc = Tools.FieldRefAccess<Base, int>(AccessTools.Field(typeof(Unrelated), \"hp\"));\n// after\nvar acc = Tools.FieldRefAccess<Base, int>(AccessTools.Field(typeof(Base), \"hp\"));","handlingStrategy":"validation","validationCode":"var fi = AccessTools.Field(typeof(Declaring), name);\nif (fi == null || !(typeof(T).IsAssignableFrom(fi.DeclaringType) || fi.DeclaringType.IsAssignableFrom(typeof(T))))\n    throw new ArgumentException(\"T and field declaring type are not assignable\");","typeGuard":"bool FieldRefCompatible<T>(FieldInfo fi) =>\n    fi != null && (typeof(T).IsAssignableFrom(fi.DeclaringType) || fi.DeclaringType.IsAssignableFrom(typeof(T)));","tryCatchPattern":"try { var acc = Tools.FieldRefAccess<T, F>(fi); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"FieldDeclaringType must be assignable\")) { /* use declaring type as T */ }","preventionTips":["Always pass the field's DeclaringType as T for FieldRefAccess","Resolve the FieldInfo from typeof(T) itself, not an unrelated type","Check mutual assignability of T and fieldInfo.DeclaringType before forming refs"],"tags":["csharp","reflection","generics"],"backgroundTag":"type-mismatch","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"}