{"record":{"id":"11fa68c8620f9b69","repo":"dotnet/wpf","slug":"sr-textpositionisfrozen-textpointer","errorCode":null,"errorMessage":"SR.TextPositionIsFrozen","messagePattern":"SR\\.TextPositionIsFrozen","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextPointer.cs","lineNumber":3951,"sourceCode":"\n            SetNodeAndEdge(node.IncrementReferenceCount(edge), edge);\n            _generation = generation;\n\n            this.CaretUnitBoundaryCache = caretUnitBoundaryCache;\n            this.IsCaretUnitBoundaryCacheValid = isCaretUnitBoundaryCacheValid;\n            _layoutGeneration = layoutGeneration;\n\n            VerifyFlags();\n            tree.AssertTree();\n            AssertState();\n        }\n\n        // Throws an exception if this TextPointer is frozen.\n        private void VerifyNotFrozen()\n        {\n            if (this.IsFrozen)\n            {\n                throw new InvalidOperationException(SR.TextPositionIsFrozen);\n            }\n        }\n\n        // Inc/decs the position ref counts on TextTreeTextNodes as the navigator\n        // is repositioned.\n        // If the new ref is to a TextTreeTextNode, the node may be split.\n        // Returns the actual node referenced, which will always be newNode,\n        // unless newNode is a TextTreeTextNode that gets split.  The caller\n        // should use the returned node to position navigators.\n        private TextTreeNode AdjustRefCounts(TextTreeNode newNode, ElementEdge newNodeEdge, TextTreeNode oldNode, ElementEdge oldNodeEdge)\n        {\n            TextTreeNode node;\n\n            // This test should walk the tree upwards to catch all errors...probably not worth the slowdown though.\n            Invariant.Assert(oldNode.ParentNode == null || oldNode.IsChildOfNode(oldNode.ParentNode), \"Trying to add ref a dead node!\");\n            Invariant.Assert(newNode.ParentNode == null || newNode.IsChildOfNode(newNode.ParentNode), \"Trying to add ref a dead node!\");\n\n            node = newNode;","sourceCodeStart":3933,"sourceCodeEnd":3969,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextPointer.cs#L3933-L3969","documentation":"TextPointer.VerifyNotFrozen is called before mutating operations on a TextPointer. TextPointers can be frozen (e.g. those returned as static positions like Document.ContentStart in some contexts, or via FrozenTextPointer implementations) and frozen pointers are immutable. Any mutation attempt on a frozen pointer throws InvalidOperationException(SR.TextPositionIsFrozen).","triggerScenarios":"Calling mutation methods (InsertTextInRun, MoveToPosition, MoveToNextContextPosition, InsertUIElement, etc.) on a frozen TextPointer instance — commonly the caret/selection pointers returned from frozen positions or pointer instances marked frozen by the editor.","commonSituations":"Storing a frozen pointer from an editor snapshot and later trying to move it; freezing via TextEditor snapshot APIs then mutating; confusing frozen positions with live selection positions (Selection.Start/CaretPosition).","solutions":["Clone the pointer into a mutable one before mutating (e.g. richTextBox.CaretPosition or use the pointer's CreatePointer/GetInsertionPosition semantics).","Check TextPointer.IsFrozen before mutating and obtain an unfrozen copy if needed.","Only use live pointers from Selection/CaretPosition for edits; treat frozen/snapshot pointers as read-only."],"exampleFix":"// before\nfrozenPointer.MoveToPosition(target, LogicalDirection.Forward);\n// after\nvar mutable = richTextBox.CaretPosition;\nmutable.MoveToPosition(target, LogicalDirection.Forward);","handlingStrategy":"type-guard","validationCode":"if (pointer.IsFrozen) pointer = richTextBox.CaretPosition; // obtain a mutable pointer","typeGuard":"static bool IsMutable(TextPointer p) => !p.IsFrozen;","tryCatchPattern":"try { pointer.MoveToPosition(target, dir); }\ncatch (InvalidOperationException) { /* pointer frozen: obtain a live pointer and retry */ }","preventionTips":["Check IsFrozen before any mutation","Treat snapshot/frozen pointers as read-only","Use Selection/CaretPosition pointers for edits"],"tags":["wpf","immutability","textpointer"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}