{"record":{"id":"ab599a4477e11639","repo":"dotnet/wpf","slug":"sr-format-sr-crossthreadaccessofunshareablefreezable","errorCode":null,"errorMessage":"SR.Format(SR.CrossThreadAccessOfUnshareableFreezable, freezable.GetType().FullName)","messagePattern":"SR\\.Format\\(SR\\.CrossThreadAccessOfUnshareableFreezable, freezable\\.GetType\\(\\)\\.FullName\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/StyleHelper.cs","lineNumber":1596,"sourceCode":"                    object o = valueLookupList.List[i].Value;\n\n                    if (o is MarkupExtension)\n                    {\n                        ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply);\n                    }\n                    else if ((freezable = o as Freezable) != null)\n                    {\n                        if (freezable.CheckAccess())\n                        {\n                            if (!freezable.IsFrozen)\n                            {\n                                ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply);\n                            }\n                        }\n                        else\n                        {\n                            Debug.Assert(!freezable.CanFreeze, \"If a freezable could have been frozen it would have been done by now.\");\n                            throw new InvalidOperationException(SR.Format(SR.CrossThreadAccessOfUnshareableFreezable, freezable.GetType().FullName));\n                        }\n                    }\n\n                    break;\n                }\n            }\n        }\n\n        //\n        //  This method\n        //  1. Adds or removes per-instance state on the container/child (push model)\n        //  2. Processes a single value that needs per-instance storage\n        //\n        internal static void ProcessInstanceValue(\n            DependencyObject    target,\n            int                 childIndex,\n            HybridDictionary    instanceValues,\n            DependencyProperty  dp,","sourceCodeStart":1578,"sourceCodeEnd":1614,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/StyleHelper.cs#L1578-L1614","documentation":"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.","triggerScenarios":"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.","commonSituations":"Producing visuals on worker threads; animations targeting resources that then cannot freeze; templates shared across Dispatcher-owned element trees in multi-window/thread scenarios.","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"],"exampleFix":"// before\nvar b = new LinearGradientBrush();\nb.BeginAnimation(LinearGradientBrush.ColorProperty, anim); // CanFreeze == false\nstyle.Resources[\"bg\"] = b;\n// after\nvar b = new LinearGradientBrush(Colors.Red, Colors.Blue, 0);\nb.Freeze(); // shareable across threads\nstyle.Resources[\"bg\"] = b;","handlingStrategy":"fallback","validationCode":"static bool ShareableAcrossThreads(Freezable f)\n{\n    if (f.IsFrozen) return true;\n    if (!f.CanFreeze) return false;\n    return Dispatcher.CurrentDispatcher.Thread == f.Dispatcher?.Thread;\n}","typeGuard":"bool IsThreadSafeResource(Freezable f) => f.IsFrozen || f.CanFreeze;","tryCatchPattern":"try { resource = FindResource(key) as Freezable; var clone = resource?.CloneCurrentValue(); clone?.Freeze(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"thread\")) { resource = CreateFreshResource(); }","preventionTips":["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"],"tags":["wpf","freezable","threading","cross-thread"],"backgroundTag":"thread-interrupted","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}