{"record":{"id":"44e455c072f7a9ee","repo":"AvaloniaUI/Avalonia","slug":"invalid-expression-type-in-binding-expression-no","errorCode":null,"errorMessage":"Invalid expression type in binding expression: {node.NodeType}.","messagePattern":"Invalid expression type in binding expression: (.+?)\\.","errorType":"validation","errorClass":"ExpressionParseException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs","lineNumber":62,"sourceCode":"    /// <exception cref=\"ExpressionParseException\">\n    /// Thrown when the expression contains unsupported operations or invalid syntax for binding\n    /// expressions.\n    /// </exception>\n    public static CompiledBindingPath BuildPath<TOut>(Expression<Func<TIn, TOut>> expression)\n    {\n        var visitor = new BindingExpressionVisitor<TIn>(expression);\n        visitor.Visit(expression);\n        return visitor._builder.Build();\n    }\n\n    protected override Expression VisitBinary(BinaryExpression node)\n    {\n        // Indexers require more work since the compiler doesn't generate IndexExpressions:\n        // they weren't in System.Linq.Expressions v1 and so must be generated manually.\n        if (node.NodeType == ExpressionType.ArrayIndex)\n            return Visit(Expression.MakeIndex(node.Left, null, [node.Right]));\n\n        throw new ExpressionParseException(0, $\"Invalid expression type in binding expression: {node.NodeType}.\");\n    }\n\n    protected override Expression VisitIndex(IndexExpression node)\n    {\n        if (node.Indexer == BindingExpressionVisitorMembers.AvaloniaObjectIndexer)\n        {\n            var property = GetValue<AvaloniaProperty>(node.Arguments[0]);\n            return Add(node.Object, node, x => x.Property(property, CreateAvaloniaPropertyAccessor));\n        }\n        else if (node.Object?.Type.IsArray == true)\n        {\n            var indexes = node.Arguments.Select(GetValue<int>).ToArray();\n            return Add(node.Object, node, x => x.ArrayElement(indexes, node.Type));\n        }\n        else if (node.Indexer?.GetMethod is not null &&\n            node.Arguments.Count == 1 &&\n            node.Arguments[0].Type == typeof(int))\n        {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs#L44-L80","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: arithmetic in compiled binding\n<TextBlock Text=\"{CompiledBinding A + B}\" />\n\n// after: bind to a computed property\n<TextBlock Text=\"{CompiledBinding Sum}\" />\n// where the view model exposes: public int Sum => A + B;","handlingStrategy":"validation","validationCode":"// Walk the expression tree to detect unsupported binary operators before building the binding\nstatic bool IsValidBindingExpression<TIn, TOut>(Expression<Func<TIn, TOut>> expr)\n{\n    var unsupported = new HashSet<ExpressionType> {\n        ExpressionType.Add, ExpressionType.Subtract, ExpressionType.Multiply,\n        ExpressionType.Divide, ExpressionType.Equal, ExpressionType.NotEqual,\n        ExpressionType.GreaterThan, ExpressionType.LessThan, ExpressionType.AndAlso,\n        ExpressionType.OrElse, ExpressionType.Modulo\n    };\n    bool valid = true;\n    expr.Body.Visit(b => {\n        if (b is BinaryExpression bin && bin.NodeType != ExpressionType.ArrayIndex\n            && unsupported.Contains(bin.NodeType))\n            valid = false;\n    });\n    return valid;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var path = BindingExpressionVisitor<TViewModel>.BuildPath<string>(expr);\n}\ncatch (ExpressionParseException ex) when (ex.Message.Contains(\"Invalid expression type\"))\n{\n    logger.LogError($\"Compiled binding lambda contains an unsupported binary operator: {ex.Message}\");\n}","preventionTips":["Keep compiled binding lambdas as simple property-access chains only.","Move computations to view-model properties.","Use IMultiValueConverter for multi-source calculations."],"tags":["avalonia","binding","compiled-binding","expression-tree","visitor","unsupported-operation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}