dotnet/wpf · error · InvalidOperationException
SR.Format(SR.CrossThreadAccessOfUnshareableFreezable…
Error message
SR.Format(SR.CrossThreadAccessOfUnshareableFreezable, freezable.GetType().FullName)
What it means
A Freezable used by the style/template (e.g. a Brush or Animation) is unfrozen and cannot be shared across threads. Because it cannot be frozen (CanFreeze == false) and is being accessed from a different thread than the one that created it, WPF throws InvalidOperationException to protect its dependency-object affinity.
Solutions
- Freeze the resource after creation: if (obj.CanFreeze) obj.Freeze();
- Ensure style resources are created and used on the same Dispatcher/thread
- Remove features that prevent freezing (animations, bindings) from shared resources
- Create a per-thread copy of the resource instead of sharing one instance
Example fix
// before var b = new LinearGradientBrush(); b.BeginAnimation(LinearGradientBrush.ColorProperty, anim); // CanFreeze == false style.Resources["bg"] = b; // after var b = new LinearGradientBrush(Colors.Red, Colors.Blue, 0); b.Freeze(); // shareable across threads style.Resources["bg"] = b;
Defensive patterns
Strategy: fallback
Validate before calling
static bool ShareableAcrossThreads(Freezable f)
{
if (f.IsFrozen) return true;
if (!f.CanFreeze) return false;
return Dispatcher.CurrentDispatcher.Thread == f.Dispatcher?.Thread;
} Type guard
bool IsThreadSafeResource(Freezable f) => f.IsFrozen || f.CanFreeze;
Try / catch
try { resource = FindResource(key) as Freezable; var clone = resource?.CloneCurrentValue(); clone?.Freeze(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("thread")) { resource = CreateFreshResource(); } Prevention
- Freeze all shared brushes/animations when CanFreeze is true
- Create resources on the UI dispatcher
- Avoid binding/animation in resources intended for cross-thread sharing
- Clone per-thread instead of sharing unfrozen instances
When it happens
Trigger: Using an unfrozen, non-shareable Freezable (e.g. a Brush with animation or bound content) inside a style applied to elements on another thread; rendering templates on a background/render thread when a resource never got frozen.
Common situations: Producing visuals on worker threads; animations targeting resources that then cannot freeze; templates shared across Dispatcher-owned element trees in multi-window/thread scenarios.
Related errors
- SR.Format(SR.Freezable_CantBeFrozen, GetType().FullName)
- SR.Freezable_AttemptToUseInnerValueWithDifferentThread
- SR.Freezable_CantFreeze
- SR.MultiThreadedCollectionChangeNotSupported
- ElementNotAvailableException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/ab599a4477e11639.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/StyleHelper.cs:1596
object o = valueLookupList.List[i].Value;
if (o is MarkupExtension)
{
ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply);
}
else if ((freezable = o as Freezable) != null)
{
if (freezable.CheckAccess())
{
if (!freezable.IsFrozen)
{
ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply);
}
}
else
{
Debug.Assert(!freezable.CanFreeze, "If a freezable could have been frozen it would have been done by now.");
throw new InvalidOperationException(SR.Format(SR.CrossThreadAccessOfUnshareableFreezable, freezable.GetType().FullName));
}
}
break;
}
}
}
//
// This method
// 1. Adds or removes per-instance state on the container/child (push model)
// 2. Processes a single value that needs per-instance storage
//
internal static void ProcessInstanceValue(
DependencyObject target,
int childIndex,
HybridDictionary instanceValues,
DependencyProperty dp,View on GitHub (pinned to 81131a70a4)