AvaloniaUI/Avalonia · error · ExpressionParseException
Invalid expression type in binding expression: {node.NodeTyp
Error message
Invalid expression type in binding expression: {node.NodeType}. What it means
Thrown by BindingExpressionVisitor.VisitBinary when a BinaryExpression node other than ArrayIndex is encountered in a compiled binding lambda. The visitor only supports array indexing as a binary operation (it converts it to an IndexExpression internally); arithmetic operators (+, -, *, /), comparisons (==, <, >), logical operators (&&, ||), and all other binary expression types are rejected because Avalonia compiled bindings model a property path, not a computation.
Source
Thrown at src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs:62
/// <exception cref="ExpressionParseException">
/// Thrown when the expression contains unsupported operations or invalid syntax for binding
/// expressions.
/// </exception>
public static CompiledBindingPath BuildPath<TOut>(Expression<Func<TIn, TOut>> expression)
{
var visitor = new BindingExpressionVisitor<TIn>(expression);
visitor.Visit(expression);
return visitor._builder.Build();
}
protected override Expression VisitBinary(BinaryExpression node)
{
// Indexers require more work since the compiler doesn't generate IndexExpressions:
// they weren't in System.Linq.Expressions v1 and so must be generated manually.
if (node.NodeType == ExpressionType.ArrayIndex)
return Visit(Expression.MakeIndex(node.Left, null, [node.Right]));
throw new ExpressionParseException(0, $"Invalid expression type in binding expression: {node.NodeType}.");
}
protected override Expression VisitIndex(IndexExpression node)
{
if (node.Indexer == BindingExpressionVisitorMembers.AvaloniaObjectIndexer)
{
var property = GetValue<AvaloniaProperty>(node.Arguments[0]);
return Add(node.Object, node, x => x.Property(property, CreateAvaloniaPropertyAccessor));
}
else if (node.Object?.Type.IsArray == true)
{
var indexes = node.Arguments.Select(GetValue<int>).ToArray();
return Add(node.Object, node, x => x.ArrayElement(indexes, node.Type));
}
else if (node.Indexer?.GetMethod is not null &&
node.Arguments.Count == 1 &&
node.Arguments[0].Type == typeof(int))
{View on GitHub (pinned to 11c5427268)
Solutions
- Move the computation into a read-only property on the view model and bind to that property instead.
- Use a multi-binding with an IMultiValueConverter if the computation involves multiple sources.
- For string formatting, use the StringFormat option on the binding rather than string concatenation in the lambda.
Example fix
// before: arithmetic in compiled binding
<TextBlock Text="{CompiledBinding A + B}" />
// after: bind to a computed property
<TextBlock Text="{CompiledBinding Sum}" />
// where the view model exposes: public int Sum => A + B; Defensive patterns
Strategy: validation
Validate before calling
// Walk the expression tree to detect unsupported binary operators before building the binding
static bool IsValidBindingExpression<TIn, TOut>(Expression<Func<TIn, TOut>> expr)
{
var unsupported = new HashSet<ExpressionType> {
ExpressionType.Add, ExpressionType.Subtract, ExpressionType.Multiply,
ExpressionType.Divide, ExpressionType.Equal, ExpressionType.NotEqual,
ExpressionType.GreaterThan, ExpressionType.LessThan, ExpressionType.AndAlso,
ExpressionType.OrElse, ExpressionType.Modulo
};
bool valid = true;
expr.Body.Visit(b => {
if (b is BinaryExpression bin && bin.NodeType != ExpressionType.ArrayIndex
&& unsupported.Contains(bin.NodeType))
valid = false;
});
return valid;
} Try / catch
try
{
var path = BindingExpressionVisitor<TViewModel>.BuildPath<string>(expr);
}
catch (ExpressionParseException ex) when (ex.Message.Contains("Invalid expression type"))
{
logger.LogError($"Compiled binding lambda contains an unsupported binary operator: {ex.Message}");
} Prevention
- Keep compiled binding lambdas as simple property-access chains only.
- Move computations to view-model properties.
- Use IMultiValueConverter for multi-source calculations.
When it happens
Trigger: Writing a compiled binding lambda that contains arithmetic: x => x.A + x.B; or a comparison: x => x.Value == 0; or any binary operator. The C# compiler accepts these, but the BindingExpressionVisitor rejects them when walking the expression tree to build the binding path.
Common situations: Developers accustomed to WPF value converters or calculated bindings attempting to do inline computation in a CompiledBinding lambda; migrating from string-based bindings that happened to work because Avalonia's string grammar also does not support arithmetic; expecting compiled bindings to support the same expressiveness as full LINQ.
Related errors
- Invalid indexer in binding expression: {node.NodeType}.
- Invalid method call in binding expression: '{node.Method.Dec
- 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/44e455c072f7a9ee.
Report an issue: GitHub.