AvaloniaUI/Avalonia · error · ExpressionParseException

Catch blocks are not allowed in binding expressions.

Error message

Catch blocks are not allowed in binding expressions.

What it means

Thrown unconditionally by BindingExpressionVisitor.VisitCatchBlock whenever a CatchBlock node appears in the expression tree. Catch blocks are produced by try-catch expressions in statement lambdas. Since compiled bindings represent a declarative property path, exception handling constructs are never valid.

Source

Thrown at src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs:205

                return Add(node.Operand, node, x => x.TypeCast(node.Type));
            }
        }
        else if (node.NodeType == ExpressionType.TypeAs)
        {
            return Add(node.Operand, node, x => x.TypeCast(node.Type));
        }

        throw new ExpressionParseException(0, $"Invalid expression type in binding expression: {node.NodeType}.");
    }

    protected override Expression VisitBlock(BlockExpression node)
    {
        throw new ExpressionParseException(0, $"Invalid expression type in binding expression: {node.NodeType}.");
    }

    protected override CatchBlock VisitCatchBlock(CatchBlock node)
    {
        throw new ExpressionParseException(0, "Catch blocks are not allowed in binding expressions.");
    }

    protected override Expression VisitConditional(ConditionalExpression node)
    {
        throw new ExpressionParseException(0, $"Invalid expression type in binding expression: {node.NodeType}.");
    }

    protected override Expression VisitDynamic(DynamicExpression node)
    {
        throw new ExpressionParseException(0, "Dynamic expressions are not allowed in binding expressions.");
    }

    protected override ElementInit VisitElementInit(ElementInit node)
    {
        throw new ExpressionParseException(0, "Element init expressions are not valid in a binding expression.");
    }

    protected override Expression VisitGoto(GotoExpression node)

View on GitHub (pinned to 11c5427268)

Solutions

  1. Use the binding's FallbackValue or TargetNullValue to handle null or error results instead of try-catch.
  2. Use the null-conditional operator (x?.Y) in the lambda for null-safe property access.
  3. Move any exception-handling logic into a view-model property and bind to that property.

Example fix

// before: try-catch in compiled binding
CompiledBinding(x => { try { return x.MightBeNull.Name; } catch { return ""; } })

// after: null-conditional + FallbackValue
<TextBlock Text="{CompiledBinding MightBeNull?.Name, FallbackValue=N/A}" />
Defensive patterns

Strategy: validation

Validate before calling

// Detect try-catch usage in a binding lambda at design time
static bool HasTryCatch<TIn, TOut>(Expression<Func<TIn, TOut>> expr)
{
    bool found = false;
    expr.Body.Visit(b =>
    {
        if (b is TryExpression) found = true;
    });
    return found;
}

Try / catch

try
{
    var path = BindingExpressionVisitor<TViewModel>.BuildPath<TProp>(expr);
}
catch (ExpressionParseException ex) when (ex.Message.Contains("Catch blocks"))
{
    logger.LogError("Try-catch is not allowed in compiled binding expressions. Use FallbackValue or null-conditional access.");
}

Prevention

When it happens

Trigger: Using a try-catch inside a statement lambda in a compiled binding: x => { try { return x.Risky; } catch { return null; } } produces a TryExpression containing CatchBlock nodes that trigger this error when visited.

Common situations: Attempting to handle null-reference or conversion exceptions inline within the binding expression; wrapping risky property access in try-catch instead of using the binding's FallbackValue or null-conditional operator; migrating error-handling code-behind into a binding lambda.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/4837e337788a374d. Report an issue: GitHub.