dotnet/wpf · error · InvalidOperationException
SR.TextSchema_IllegalHyperlinkChild (nextElement.GetType())
Error message
SR.TextSchema_IllegalHyperlinkChild (nextElement.GetType())
What it means
HasIllegalHyperlinkDescendant scans a position range for Hyperlink or AnchoredBlock elements that would illegally descend from a hyperlink. If one is found and throwIfIllegalDescendent is true, an InvalidOperationException is thrown naming the offending element's type. It enforces the rule that Hyperlink content cannot contain nested Hyperlinks or block-level AnchoredBlocks.
Solutions
- Before applying a Hyperlink over a range, remove/flatten existing nested Hyperlink elements within the selection
- Split the enclosing Hyperlink so the edited range lies outside any existing link scope (TextRangeEdit helpers do this; replicate it for custom code)
- Replace illegal AnchoredBlock descendants with inline equivalents (Run/Span) inside link content
- Catch InvalidOperationException, locate the nested element via the message type, and restructure the tree before retrying the edit
Example fix
// before TextRange selection = new TextRange(start, end); // selection contains an existing Hyperlink selection.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Blue); // edit crossing Hyperlink boundary -> HasIllegalHyperlinkDescendant throws when creating nested link // after foreach (var hl in FindHyperlinks(selection)) FlattenHyperlink(hl); // unwrap nested links first selection.ApplyPropertyValue(...);
Defensive patterns
Strategy: validation
Validate before calling
static bool RangeHasIllegalLinkDescendant(TextPointer start, TextPointer end) => /* scan with GetNextContextPosition; throw-free probe via throwIfIllegalDescendent:false */ HasIllegalHyperlinkDescendant(start, end, false);
Type guard
static bool IsSafeLinkContent(TextElement e) => !(e is Hyperlink) && !(e is AnchoredBlock);
Try / catch
try { ApplyLinkFormatting(range); } catch (InvalidOperationException ex) when (ex.Message.Contains("IllegalHyperlinkChild")) { SplitEnclosingHyperlinks(range); ApplyLinkFormatting(range); } Prevention
- Unwrap existing Hyperlinks in a selection before applying link formatting
- Split Spans/Hyperlinks at range boundaries before edits
- Run probe scans with throw flags off in edit pipelines
When it happens
Trigger: Text edits (e.g. applying Hyperlink formatting over a selection, TextRange save/paste, splitting operations) that would leave a Hyperlink or AnchoredBlock (Paragraph/Table/List/Floater/Figure/Section) inside an existing Hyperlink's scope; detected via GetNextContextPosition scan from the range start.
Common situations: Applying link formatting to a selection that already contains a link; paste operations merging content inside a hyperlink; code that splits a Span at a Hyperlink boundary producing nested links.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- SR.Format(SR.TextSchema_CannotSplitElement…
- SR.HyperLinkTargetNotFound
- SR.TextRangeEdit_InvalidStructuralPropertyApply (property…
- SR.TextSchema_CannotSplitElement (ancestor type name)
- SR.TextSchema_IllegalHyperlinkChild (childType)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/62f4551c201de9eb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextSchema.cs:897
// It this context, the element or one of its ancestors is a Hyperlink.
private static bool HasIllegalHyperlinkDescendant(TextElement element, bool throwIfIllegalDescendent)
{
TextPointer start = element.ElementStart;
TextPointer end = element.ElementEnd;
while (start.CompareTo(end) < 0)
{
TextPointerContext forwardContext = start.GetPointerContext(LogicalDirection.Forward);
if (forwardContext == TextPointerContext.ElementStart)
{
TextElement nextElement = (TextElement)start.GetAdjacentElement(LogicalDirection.Forward);
if (nextElement is Hyperlink ||
nextElement is AnchoredBlock)
{
if (throwIfIllegalDescendent)
{
throw new InvalidOperationException(SR.Format(SR.TextSchema_IllegalHyperlinkChild, nextElement.GetType()));
}
return true;
}
}
start = start.GetNextContextPosition(LogicalDirection.Forward);
}
return false;
}
private static bool AreBrushesEqual(Brush brush1, Brush brush2)
{
SolidColorBrush solidBrush1 = brush1 as SolidColorBrush;
if (solidBrush1 != null)
{
return solidBrush1.Color.Equals(((SolidColorBrush)brush2).Color);
}
elseView on GitHub (pinned to 81131a70a4)