dotnet/wpf · error · InvalidOperationException

SR.TwoWayBindingNeedsPath

Error message

SR.TwoWayBindingNeedsPath

What it means

A reflective (TwoWay or OneWayToSource) binding with no path (Path empty/null and no XPath) cannot know which source property to write back to, so CreateBindingExpression throws this InvalidOperationException. Such a binding would push the whole target value to an undefined source location.

Solutions

  1. Provide a non-empty Path (or XPath for XML) when the binding mode is TwoWay or OneWayToSource
  2. Set Mode to OneWay/OneTime if you truly intend to bind to the whole DataContext with no path
  3. Verify ResolvePropertyDefaultSettings: some properties default to TwoWay; make the mode explicit

Example fix

// before
var b = new Binding { Mode = BindingMode.TwoWay }; // throws TwoWayBindingNeedsPath
// after
var b = new Binding("Value") { Mode = BindingMode.TwoWay };
Defensive patterns

Strategy: validation

Validate before calling

bool reflective = b.Mode is BindingMode.TwoWay or BindingMode.OneWayToSource;
if (reflective && b.XPath == null && string.IsNullOrEmpty(b.Path?.Path)) throw new InvalidOperationException("TwoWay binding requires a non-empty Path");

Type guard

static bool HasPath(Binding b) => b.XPath != null || !string.IsNullOrEmpty(b.Path?.Path);

Try / catch

try { target.SetBinding(dp, b); } catch (InvalidOperationException ex) when (ex.Message.Contains("Two-Way") || ex.Message.Contains("path")) { b.Path = new PropertyPath("Value"); target.SetBinding(dp, b); }

Prevention

When it happens

Trigger: Creating a Binding with Mode=TwoWay or OneWayToSource while Path is null/empty and XPath is null — e.g. new Binding { Mode = BindingMode.TwoWay } used with SetBinding, or a Path of "" with reflective mode.

Common situations: Constructing bindings to bind the DataContext itself but accidentally leaving Mode TwoWay (default source-resolution default); copy-pasted binding code with path removed; dynamic binding builders that skip path when it looks 'optional'.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/de7c0e9670c4bbd6. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingExpression.cs:404

        internal static BindingExpression CreateBindingExpression(DependencyObject d,
                                                DependencyProperty dp,
                                                Binding binding,
                                                BindingExpressionBase parent)
        {
            FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;

            if ((fwMetaData != null && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
                throw new ArgumentException(SR.Format(SR.PropertyNotBindable, dp.Name), nameof(dp));

            // create the BindingExpression
            BindingExpression bindExpr = new BindingExpression(binding, parent);

            bindExpr.ResolvePropertyDefaultSettings(binding.Mode, binding.UpdateSourceTrigger, fwMetaData);

            // Two-way Binding with an empty path makes no sense
            if (bindExpr.IsReflective && binding.XPath == null &&
                    (binding.Path == null || String.IsNullOrEmpty(binding.Path.Path)))
                throw new InvalidOperationException(SR.TwoWayBindingNeedsPath);

            return bindExpr;
        }


        // Note: For Nullable types, DefaultValueConverter is created for the inner type of the Nullable.
        //       Nullable "Drill-down" service is not provided for user provided Converters.
        internal void SetupDefaultValueConverter(Type type)
        {
            if (!UseDefaultValueConverter)
                return;

            if (IsInMultiBindingExpression)
            {
                Converter = null;
                _sourceType = type;
            }
            else if (type != null && type != _sourceType)

View on GitHub (pinned to 81131a70a4)