spectreconsole/spectre.console · error · InvalidOperationException
Encountered malformed markup tag at position {pos}.
Error message
Encountered malformed markup tag at position {pos}. What it means
ThrowMalformed is the catch-all for malformed opening tags in MarkupTokenizer.ReadMarkup: it fires on EOF reached before the tag closes, an unexpected character after `[/` (the closer must be `[/]`), an unescaped `[` inside a tag body, or input that opens `[` but never supplies a valid `]` terminator. The reported position points at the offending location.
Source
Thrown at src/Spectre.Console.Ansi/AnsiMarkup.cs:434
{
currentStylePartCanContainMarkup =
(builder.Length == LinkPrefix.Length || builder[^(LinkPrefix.Length + 1)] == ' ')
&& builder.ToString(builder.Length - LinkPrefix.Length, LinkPrefix.Length)
.Equals(LinkPrefix, StringComparison.OrdinalIgnoreCase);
}
}
if (_reader.Eof)
{
ThrowMalformed(_reader.Position);
}
return new MarkupToken(MarkupTokenKind.Open, builder.ToString(), position);
}
[DoesNotReturn]
private static void ThrowMalformed(int pos) =>
throw new InvalidOperationException($"Encountered malformed markup tag at position {pos}.");
}
View on GitHub (pinned to 0acc92fada)
Solutions
- Ensure every tag is fully formed: `[...]` with a single well-formed body and a closing `]`
- Use `[/]` exactly for closers (no other content between the brackets)
- Escape any literal `[` or `]` that should appear as text inside a tag context
- Validate or try/catch around AnsiMarkup.Parse for dynamic markup
Example fix
// before
AnsiMarkup.Parse("[redtext"); // missing closing bracket
// after
AnsiMarkup.Parse("[red]text[/]"); Defensive patterns
Strategy: try-catch
Validate before calling
// Lightweight sanity check that tags are closed:
public static bool TagsLookWellFormed(string markup)
=> !Regex.IsMatch(markup, @"\[[^\]]*$") && !Regex.IsMatch(markup, @"\[/[^\]]"); Try / catch
try { var segments = AnsiMarkup.Parse(markup); }
catch (InvalidOperationException ex) when (ex.Message.Contains("malformed markup tag"))
{ /* log position from message, fall back to plain text */ } Prevention
- Build tags programmatically rather than string-concatenating
- Always supply the closing `]` for every `[`
- Validate dynamically assembled markup before rendering
When it happens
Trigger: Inputs such as `"[red"` (no closing bracket), `"[/x"` (bad closer), `"[a[b]"` (unescaped `[` inside tag), or `"[link="` truncated at EOF.
Common situations: Hand-written markup with a typo; dynamically built tags with a missing `]`; truncated strings from a buffer; copy-paste that lost the closing bracket.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Encountered closing tag when none was expected near position
- Unbalanced markup stack. Did you forget to close a tag?
- Encountered unknown markup token.
- Encountered unescaped ']' token at position {_reader.Positio
- A link has already been set.
AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13).
Data as JSON: /api/errors/0280a049db56c827.
Report an issue: GitHub.