dotnet/wpf · error · ArgumentException
SR.SharingNonSharableExpression
Error message
SR.SharingNonSharableExpression
What it means
During SetValueCommon, if the new value is an Expression (binding/expression markup extension) that is not Attachable (i.e. its Attachable property is false), WPF throws ArgumentException(SR.SharingNonSharableExpression). Expressions must be attachable to be shared/assigned onto dependency properties; non-attachable expressions cannot be shared across DependencyObjects or attached in the current context.
Solutions
- Create a fresh Binding/Expression instance per target instead of sharing one instance.
- Use BindingOperations.SetBinding with a properly constructed Binding whose properties allow attachment.
- If writing a custom Expression/MarkupExtension, implement and set Attachable correctly (allow multiple attach or clone on attach).
Example fix
// before
var binding = new Binding("Name") { Source = vm };
control1.SetBinding(TextBlock.TextProperty, binding);
control2.SetBinding(TextBlock.TextProperty, binding); // shared
// after
control1.SetBinding(TextBlock.TextProperty, new Binding("Name") { Source = vm });
control2.SetBinding(TextBlock.TextProperty, new Binding("Name") { Source = vm }); Defensive patterns
Strategy: type-guard
Validate before calling
if (value is Expression expr && !expr.Attachable)
throw new InvalidOperationException("Expression is not attachable; create a new instance per target."); Type guard
bool IsShareableExpression(object v) => v is not Expression e || e.Attachable;
Try / catch
try { target.SetValue(TargetProperty, exprValue); }
catch (ArgumentException ex) when (ex.Message.Contains("attachable") || ex.Message.Contains("Expression"))
{
target.SetBinding(TargetProperty, CreateFreshBinding()); // new instance per target
} Prevention
- Create one Binding/Expression instance per target; never share across DependencyObjects.
- Use BindingOperations.SetBinding rather than raw SetValue for bindings.
- When authoring custom expressions, implement Attachable (or clone on attach).
When it happens
Trigger: Assigning an expression instance (BindingBase, custom Expression) with Attachable == false to a DP via SetValue; reusing a single expression object across multiple targets when it was created non-shareable (e.g. a Binding whose-source state forbids sharing).
Common situations: Caching one Binding object and applying it to many controls; programmatically building expressions with incorrect internal flags; expressions deserialized from XAML that lost attachable state.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- InvalidEnumArgumentException("value", (int) value…
- InvalidEnumArgumentException("value", (int) value…
- SR.StyleValueOfExpressionNotSupported
- SR.UnknownExpressionMode
- " }} " element found. Expected fixed page element ( }} ).
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/3cf4da1f683d9434.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs:666
// First try to validate the value; only after this validation fails should we
// do the more expensive checks (type checks) for the less common scenarios
if (!newValueHasExpressionMarker)
{
bool isValidValue = isInternal ? dp.IsValidValueInternal(value) : dp.IsValidValue(value);
// for properties of type "object", we have to always check for expression & deferredreference
if (!isValidValue || dp.IsObjectType)
{
// 2nd most common is expression
newExpr = value as Expression;
if (newExpr != null)
{
// For Expressions, perform additional validation
// Make sure Expression is "attachable"
if (!newExpr.Attachable)
{
throw new ArgumentException(SR.SharingNonSharableExpression);
}
// Check dispatchers of all Sources
// CALLBACK
newSources = newExpr.GetSources();
ValidateSources(this, newSources, newExpr);
}
else
{
// and least common is DeferredReference
isDeferredReference = (value is DeferredReference);
if (!isDeferredReference)
{
if (!isValidValue)
{
// it's not a valid value & it's not an expression, so throw
throw new ArgumentException(SR.Format(SR.InvalidPropertyValue, value, dp.Name));
}View on GitHub (pinned to 81131a70a4)