dotnet/wpf · error · InvalidOperationException
SR.TextPositionIsFrozen
Error message
SR.TextPositionIsFrozen
What it means
This InvalidOperationException is thrown by DocumentSequenceTextPointer.ITextPointer.MoveByOffset when the text pointer is frozen. Frozen pointers (created with ITextPointer.Freeze) are immutable; any mutation API that would change their position must reject the call. The library throws eagerly rather than silently ignoring the move.
Solutions
- Create a mutable clone before moving: call CreatePointer() (or CreateStaticPointer for read-only use) on the frozen pointer and call MoveByOffset on the clone.
- Remove the unnecessary Freeze() call if the pointer still needs to be moved.
- Guard with pointer.IsFrozen and only move unfrozen pointers.
Example fix
// before
frozenPointer.MoveByOffset(3);
// after
if (!frozenPointer.IsFrozen)
frozenPointer.MoveByOffset(3);
else
var movable = frozenPointer.CreatePointer();
movable.MoveByOffset(3); Defensive patterns
Strategy: try-catch
Validate before calling
if (pointer == null || pointer.IsFrozen) pointer = pointer?.CreatePointer();
Type guard
bool IsMovable(ITextPointer p) => p is { IsFrozen: false }; Try / catch
try { pointer.MoveByOffset(offset); } catch (InvalidOperationException) { var clone = pointer.CreatePointer(); clone.MoveByOffset(offset); } Prevention
- Never call mutation APIs (Move*, InsertText) on frozen pointers.
- Clone with CreatePointer() before navigating a pointer you did not create yourself.
- Check IsFrozen in helper utilities that accept ITextPointer.
When it happens
Trigger: Calling MoveByOffset (or MoveToLineBoundary/MoveByCharacter variants that route through it) on a DocumentSequenceTextPointer whose _isFrozen flag is true, i.e. one on which Freeze() was previously called.
Common situations: Sharing a cached pointer across code paths where one consumer froze it; holding a pointer snapshot for comparison/editing detection and then attempting to navigate with it; editor/text-selection code that freezes pointers for stability checks and later reuses them for movement.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.NoElement
- Animation_Invalid_DefaultValue
- ArgumentNullException(paramName)
- Cannot remove signature from read-only file.
- Image_EncoderNoColorContext
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fbe2cac17217a458.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/DocumentSequenceTextPointer.cs:453
#region TextNavigator Methods
/// <summary>
/// <see cref="ITextPointer.MoveByOffset"/>
/// </summary>
bool ITextPointer.MoveToNextContextPosition(LogicalDirection direction)
{
Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");
return DocumentSequenceTextPointer.iScan(this, direction);
}
/// <summary>
/// <see cref="ITextPointer.MoveByOffset"/>
/// </summary>
int ITextPointer.MoveByOffset(int offset)
{
if (_isFrozen) throw new InvalidOperationException(SR.TextPositionIsFrozen);
if (DocumentSequenceTextPointer.iScan(this, offset))
{
return offset;
}
else
{
return 0;
}
}
/// <summary>
/// <see cref="ITextPointer.MoveToPosition"/>
/// </summary>
void ITextPointer.MoveToPosition(ITextPointer position)
{
DocumentSequenceTextPointer tp = this.AggregatedContainer.VerifyPosition(position);
View on GitHub (pinned to 81131a70a4)