pardeike/Harmony · error · ArgumentException
Invalid Expression. Expression should consist of a field…
Error message
Invalid Expression. Expression should consist of a field access only.
What it means
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.
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
Example fix
// before
var f = SymbolExtensions.GetFieldInfo(() => instance.SomeAutoProperty); // property => throws
// after
var f = typeof(Instance).GetField("someField", BindingFlags.NonPublic | BindingFlags.Instance); Defensive patterns
Strategy: validation
Validate before calling
Expression body = expr.Body;
while (body is UnaryExpression { NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked } u) body = u.Operand;
bool isField = body is MemberExpression { Member: FieldInfo }; Type guard
static FieldInfo TryGetFieldInfo(LambdaExpression e)
{
Expression b = e.Body;
while (b is UnaryExpression u) b = u.Operand;
return b is MemberExpression me && me.Member is FieldInfo fi ? fi : null;
} Try / catch
FieldInfo fi;
try { fi = SymbolExtensions.GetFieldInfo(() => instance.someField); }
catch (ArgumentException) { fi = typeof(T).GetField("someField", BindingFlags.NonPublic | BindingFlags.Instance); } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid Expression. Expression should consist of a Method…
- must be specified as 'Namespace.Type1.Type2:MemberName
- Field must be static
- The type must declare an empty constructor (the constructor…
- Value cannot be null. (Parameter 'fromMethod')
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/72b5ad487ae73e21.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/SymbolExtensions.cs:76
///
public static FieldInfo GetFieldInfo<T>(Expression<Func<T>> expression) => GetFieldInfo((LambdaExpression)expression);
/// <summary>Given a lambda expression that accesses a field, returns the field info</summary>
/// <param name="expression">The lambda expression using the field</param>
/// <returns>The field in the lambda expression</returns>
///
public static FieldInfo GetFieldInfo(LambdaExpression expression)
{
if (expression is null)
throw new ArgumentNullException(nameof(expression));
var body = expression.Body;
while (body is UnaryExpression { NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked } unaryExpression)
body = unaryExpression.Operand;
if (body is MemberExpression memberExpression && memberExpression.Member is FieldInfo field)
return field;
throw new ArgumentException("Invalid Expression. Expression should consist of a field access only.", nameof(expression));
}
}
}
View on GitHub (pinned to e7872dc170)