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
- Provide a non-empty Path (or XPath for XML) when the binding mode is TwoWay or OneWayToSource
- Set Mode to OneWay/OneTime if you truly intend to bind to the whole DataContext with no path
- 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
- Always set Path for TwoWay/OneWayToSource bindings
- Remember some DPs default to TwoWay (e.g. TextBox.Text) — supply a path even in defaults
- Centralize binding construction to validate mode/path pairs
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
- ArgumentNullException(nameof(assemblyPath))
- ArgumentNullException(nameof(value))
- (no message) NotSupportedException
- NotImplementedException (ConvertBack not supported)
- NotImplementedException (ConvertBack not supported)
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)