{"record":{"id":"72b5ad487ae73e21","repo":"pardeike/Harmony","slug":"invalid-expression-expression-should-consist-of-a-field","errorCode":null,"errorMessage":"Invalid Expression. Expression should consist of a field access only.","messagePattern":"Invalid Expression\\. Expression should consist of a field access only\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/SymbolExtensions.cs","lineNumber":76,"sourceCode":"\t\t///\r\n\t\tpublic static FieldInfo GetFieldInfo<T>(Expression<Func<T>> expression) => GetFieldInfo((LambdaExpression)expression);\r\n\r\n\t\t/// <summary>Given a lambda expression that accesses a field, returns the field info</summary>\r\n\t\t/// <param name=\"expression\">The lambda expression using the field</param>\r\n\t\t/// <returns>The field in the lambda expression</returns>\r\n\t\t///\r\n\t\tpublic static FieldInfo GetFieldInfo(LambdaExpression expression)\r\n\t\t{\r\n\t\t\tif (expression is null)\r\n\t\t\t\tthrow new ArgumentNullException(nameof(expression));\r\n\r\n\t\t\tvar body = expression.Body;\r\n\t\t\twhile (body is UnaryExpression { NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked } unaryExpression)\r\n\t\t\t\tbody = unaryExpression.Operand;\r\n\r\n\t\t\tif (body is MemberExpression memberExpression && memberExpression.Member is FieldInfo field)\r\n\t\t\t\treturn field;\r\n\t\t\tthrow new ArgumentException(\"Invalid Expression. Expression should consist of a field access only.\", nameof(expression));\r\n\t\t}\r\n\t}\r\n}\r\n","sourceCodeStart":58,"sourceCodeEnd":80,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/SymbolExtensions.cs#L58-L80","documentation":"AccessTools.GetFieldInfo extracts a FieldInfo from a lambda, but only when the lambda body (after stripping Convert/ConvertChecked wrappers) is a member expression referencing a field. If the body is a property, method, or something else entirely, ArgumentException is thrown because the expression must consist of a field access only.","triggerScenarios":"Calling SymbolExtensions.GetFieldInfo(() => obj.SomeProperty) (property, not field), (() => obj.Method()) (call), or a lambda whose body is a call or index expression; also when the member expression does not resolve to a FieldInfo after unary conversions are unwrapped.","commonSituations":"The target member was refactored from a public field to a property (very common when a library updates); developer picked the wrong helper (GetFieldInfo vs GetPropertyInfo); boxing conversion over a non-field member.","solutions":["Confirm the lambda accesses an actual C# field, e.g. GetFieldInfo(() => instance.someField) or a static field GetFieldInfo(() => SomeType.staticField)","If the member is a property, use AccessTools.Property / GetPropertyInfo or the corresponding SymbolExtensions helper instead","If the member changed from field to property upstream, switch the helper or pin to the older type version","As a fallback use typeof(T).GetField(\"name\", BindingFlags) directly"],"exampleFix":"// before\nvar f = SymbolExtensions.GetFieldInfo(() => instance.SomeAutoProperty); // property => throws\n// after\nvar f = typeof(Instance).GetField(\"someField\", BindingFlags.NonPublic | BindingFlags.Instance);","handlingStrategy":"validation","validationCode":"Expression body = expr.Body;\nwhile (body is UnaryExpression { NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked } u) body = u.Operand;\nbool isField = body is MemberExpression { Member: FieldInfo };","typeGuard":"static FieldInfo TryGetFieldInfo(LambdaExpression e)\n{\n    Expression b = e.Body;\n    while (b is UnaryExpression u) b = u.Operand;\n    return b is MemberExpression me && me.Member is FieldInfo fi ? fi : null;\n}","tryCatchPattern":"FieldInfo fi;\ntry { fi = SymbolExtensions.GetFieldInfo(() => instance.someField); }\ncatch (ArgumentException) { fi = typeof(T).GetField(\"someField\", BindingFlags.NonPublic | BindingFlags.Instance); }","preventionTips":["Check whether the member is a field or a property (fields are usually private; properties often wrap them)","Use GetPropertyInfo/AccessTools.Property for properties instead of GetFieldInfo","When a target library refactors a field into a property, update the helper used, not just the lambda"],"tags":["argument-exception","lambda-expression","reflection"],"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"}