AvaloniaUI/Avalonia · error · InvalidOperationException

BindingExpression has not been started.

Error message

BindingExpression has not been started.

What it means

GetValue() on an UntypedBindingExpressionBase returns the cached current value, but only after the expression has been started (attached to a target via the ValueStore). If IsRunning is false the binding is not yet wired up, so there is no meaningful value, and the method throws InvalidOperationException.

Source

Thrown at src/Avalonia.Base/Data/Core/UntypedBindingExpressionBase.cs:128

        _frame = null;
        sink.OnCompleted(this);
        frame?.OnEntryDisposed(this);
    }

    /// <summary>
    /// Gets the current value of the binding expression.
    /// </summary>
    /// <returns>
    /// The current value or <see cref="AvaloniaProperty.UnsetValue"/> if the binding was unable
    /// to read a value.
    /// </returns>
    /// <exception cref="InvalidOperationException">
    /// The binding expression has not been started.
    /// </exception>
    public object? GetValue()
    {
        if (!IsRunning)
            throw new InvalidOperationException("BindingExpression has not been started.");
        return _value;
    }

    /// <summary>
    /// Gets the current value of the binding expression or the default value for the target property.
    /// </summary>
    /// <returns>
    /// The current value or the target property default.
    /// </returns>
    public object? GetValueOrDefault()
    {
        var result = GetValue();
        if (result == AvaloniaProperty.UnsetValue)
            result = GetCachedDefaultValue();
        return result;
    }

    /// <summary>

View on GitHub (pinned to 11c5427268)

Solutions

  1. Apply the binding to a target AvaloniaObject (e.g. via `control.Bind(property, binding)`) so the expression starts before you read it.
  2. Use GetValueOrDefault() if you only need the current value or the property default and cannot guarantee the expression started.
  3. In tests, drive the binding through a real AvaloniaObject/ValueStore rather than probing a detached expression.

Example fix

// before:
var expr = myBinding.CreateInstance(target, prop, anchor);
var val = expr.GetValue(); // throws

// after:
target.Bind(prop, myBinding);
// let the value store start the expression, then read the property:
var val = target.GetValue(prop);
Defensive patterns

Strategy: validation

Validate before calling

if (!expr.IsRunning)
    throw new InvalidOperationException("Start the expression before reading.");
var v = expr.GetValue();

Type guard

static bool HasStarted(UntypedBindingExpressionBase e) => e.IsRunning;

Try / catch

try { var v = expr.GetValue(); }
catch (InvalidOperationException) when (!expr.IsRunning)
{
    // expression not attached; read target property default instead
}

Prevention

When it happens

Trigger: Calling `expression.GetValue()` on a binding expression that was constructed but never attached to an AvaloniaObject target (no Start/Attach was invoked). Reading the value of an expression before the ValueStore has started it.

Common situations: Unit tests that create a binding expression and immediately read its value without applying it to a control. Calling GetValue() on a freshly instantiated expression returned from IBinding.CreateInstance before it is attached.

Related errors


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