AvaloniaUI/Avalonia · error · ExpressionParseException
Invalid method call in binding expression: '{node.Method.Dec
Error message
Invalid method call in binding expression: '{node.Method.DeclaringType}.{node.Method.Name}'. What it means
Thrown by BindingExpressionVisitor.VisitMethodCall when a method invocation in the compiled binding lambda does not match any of the recognized method patterns: (1) get_Item (indexer getter), (2) Get (multi-dimensional array getter), (3) StreamBinding extension methods, or (4) ReflectionExtensions.CreateDelegate. Any other method call is rejected because compiled bindings represent a property path, not arbitrary code execution.
Source
Thrown at src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs:165
{
return Add(instance, node, x => x.StreamTask());
}
else if (instanceType is not null && ObservableStreamPlugin.MatchesType(instanceType))
{
return Add(instance, node, x => x.StreamObservable());
}
}
else if (method == BindingExpressionVisitorMembers.CreateDelegateMethod)
{
var methodInfo = GetValue<MethodInfo>(node.Object!);
var delegateType = GetValue<Type>(node.Arguments[0]);
return Add(node.Arguments[1], node, x => x.Method(
methodInfo.MethodHandle,
delegateType.TypeHandle,
acceptsNull: false));
}
throw new ExpressionParseException(0, $"Invalid method call in binding expression: '{node.Method.DeclaringType}.{node.Method.Name}'.");
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == _rootExpression.Parameters[0] && _head is null)
_head = node;
return base.VisitParameter(node);
}
protected override Expression VisitUnary(UnaryExpression node)
{
if (node.NodeType == ExpressionType.Not && node.Type == typeof(bool))
{
return Add(node.Operand, node, x => x.Not());
}
else if (node.NodeType == ExpressionType.Convert)
{
// Allow reference type casts (both upcasts and downcasts) but reject value type conversionsView on GitHub (pinned to 11c5427268)
Solutions
- Move the method call into a property on the view model: 'public int ItemCount => Items.Count();' and bind to ItemCount.
- For formatting, use the binding's StringFormat converter instead of calling ToString() in the lambda.
- For stream bindings, use the dedicated '^' stream operator or the StreamBinding() extension method which IS supported.
Example fix
// before: method call in compiled binding
<TextBlock Text="{CompiledBinding Items.Count()}" />
// after: expose as property
<TextBlock Text="{CompiledBinding ItemCount}" />
// view model:
public int ItemCount => Items.Count; Defensive patterns
Strategy: validation
Validate before calling
// Detect method calls in a binding lambda that are not recognized stream/indexer patterns
static bool HasUnsupportedMethodCall<TIn, TOut>(Expression<Func<TIn, TOut>> expr)
{
var allowedMethods = new HashSet<string> { "get_Item", "Get" };
bool found = false;
expr.Body.Visit(b =>
{
if (b is MethodCallExpression mc
&& !allowedMethods.Contains(mc.Method.Name)
&& mc.Method.DeclaringType != typeof(StreamBindingExtensions))
found = true;
});
return found;
} Try / catch
try
{
var path = BindingExpressionVisitor<TViewModel>.BuildPath<TProp>(expr);
}
catch (ExpressionParseException ex) when (ex.Message.Contains("Invalid method call"))
{
logger.LogError($"Compiled binding contains a method call that is not a recognized indexer or stream operation: {ex.Message}");
} Prevention
- Never call methods in a compiled binding lambda — only property access, indexing, casts, and !.
- Move method results (Count, ToString, etc.) into view-model properties.
- Use IValueConverter for transformations that must happen at binding time.
When it happens
Trigger: Calling a method in the binding lambda such as x => x.Items.Count() (LINQ method), x => x.Name.ToString(), x => x.Value.ToString(CultureInfo), or any instance/static method call. The C# compiler happily compiles these, but the visitor cannot translate them into a CompiledBindingPath.
Common situations: Using LINQ methods like Count(), First(), Select() in a compiled binding; calling ToString() or other formatting methods; expecting compiled bindings to support method chaining like a fluent API; migrating from code-behind property access to bindings without adjusting the expression.
Related errors
- Invalid expression type in binding expression: {node.NodeTyp
- Invalid indexer in binding expression: {node.NodeType}.
- Catch blocks are not allowed in binding expressions.
- Dynamic expressions are not allowed in binding expressions.
- Element init expressions are not valid in a binding expressi
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/035e83139579876a.
Report an issue: GitHub.