dotnet/wpf · error · ArgumentException
SR.SourceChangeExpressionMismatch
Error message
SR.SourceChangeExpressionMismatch
What it means
Thrown by DependencyObject.ChangeExpressionSources when the local value stored on the target DependencyObject is no longer the Expression instance whose sources are being re-evaluated. The property system detected a mismatch between the expression it was asked to re-source and the actual local value, indicating the expression was replaced or cleared concurrently or out of order.
Solutions
- Verify the expression is still the current local value (ReadLocalValue) before changing its sources
- Re-set the expression with SetValue instead of calling ChangeExpressionSources on a stale instance
- Guard against re-entrant property changes while updating expression sources
- Use standard Binding/BindingExpression APIs rather than raw Expression plumbing
Example fix
// before
expr.ChangeSources(d, dp, newSources); // stale expr
// after
if (ReferenceEquals(d.ReadLocalValue(dp), expr)) { expr.ChangeSources(d, dp, newSources); } Defensive patterns
Strategy: validation
Validate before calling
if (!ReferenceEquals(d.ReadLocalValue(dp), expr)) throw new InvalidOperationException("Expression no longer current");
expr.ChangeSources(d, dp, sources); Type guard
static bool IsCurrentExpression(DependencyObject d, DependencyProperty dp, Expression expr) => ReferenceEquals(d.ReadLocalValue(dp), expr);
Try / catch
try { expr.ChangeSources(d, dp, sources); }
catch (ArgumentException) { d.SetValue(dp, expr); /* re-install then retry */ } Prevention
- Verify ReadLocalValue still returns your expression before source changes
- Avoid replacing expressions and changing sources concurrently
- Prefer standard Binding APIs over custom Expression plumbing
When it happens
Trigger: Calling SetValue with an Expression, then modifying its sources via ChangeExpressionSources when the local value slot no longer reference-equals that expression; re-entrancy or double-set of expressions on the same property.
Common situations: Custom binding/expression implementations that call ChangeExpressionSources after the expression was overwritten, race conditions between expression replacement and source updates, misuse of internal expression APIs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- SR.DefaultValueMayNotBeExpression
- Animation_CalculatedValueIsInvalidForProperty
- Animation_DependencyPropertyIsNotAnimatable
- InvalidOperationException()
- NotImplementedException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/8c63e66b46209730.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs:1039
object value = entry.IsCoercedWithCurrentValue ? entry.ModifiedValue.CoercedValue : entry.LocalValue;
return !object.ReferenceEquals(value, DependencyProperty.UnsetValue);
}
//
// Changes the sources of an existing Expression
//
internal static void ChangeExpressionSources(Expression expr, DependencyObject d, DependencyProperty dp, DependencySource[] newSources)
{
if (!expr.ForwardsInvalidations)
{
// Get current local value (should be provided Expression)
// (No need to go through read local callback, just checking
// for presence of Expression)
EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex);
if (!entryIndex.Found || (d._effectiveValues[entryIndex.Index].LocalValue != expr))
{
throw new ArgumentException(SR.SourceChangeExpressionMismatch);
}
}
// Get current sources
// CALLBACK
DependencySource[] currentSources = expr.GetSources();
// Remove old
if (currentSources != null)
{
UpdateSourceDependentLists(d, dp, currentSources, expr, false); // Remove
}
// Add new
if (newSources != null)
{
UpdateSourceDependentLists(d, dp, newSources, expr, true); // Add
}View on GitHub (pinned to 81131a70a4)