spectreconsole/spectre.console · error · InvalidOperationException
Encountered unescaped ']' token at position {_reader.Positio
Error message
Encountered unescaped ']' token at position {_reader.Position} What it means
Inside MarkupTokenizer.ReadText, a literal `]` is only legal when immediately followed by another `]` (the `]]` escape for a literal close bracket). A lone `]` with any following character (or EOF) throws, reporting the reader position.
Source
Thrown at src/Spectre.Console.Ansi/AnsiMarkup.cs:333
var position = _reader.Position;
var builder = new StringBuilder();
while (!_reader.Eof)
{
var current = _reader.Peek();
if (current == '[')
{
// markup encountered. Stop processing.
break;
}
// If we find a closing tag (']') there must be two of them.
if (current == ']')
{
_reader.Read();
if (_reader.Peek() != ']')
{
throw new InvalidOperationException(
$"Encountered unescaped ']' token at position {_reader.Position}");
}
}
builder.Append(_reader.Read());
}
return new MarkupToken(MarkupTokenKind.Text, builder.ToString(), position);
}
private MarkupToken ReadMarkup()
{
var position = _reader.Position;
// Read initial opening bracket
_reader.Read();
if (_reader.Eof)View on GitHub (pinned to 0acc92fada)
Solutions
- Escape dynamic text with AnsiMarkup.Escape(text), which turns `]` into `]]` (and `[` into `[[`)
- Manually double any literal `]` in static markup strings
- Avoid splicing raw data into markup; render plain text separately
Example fix
// before
AnsiMarkup.Write($"Result: {userText}"); // breaks if userText contains ']'
// after
AnsiMarkup.Write($"Result: {AnsiMarkup.Escape(userText)}"); Defensive patterns
Strategy: validation
Validate before calling
// Escape dynamic text before embedding; this is the canonical prevention: var safe = AnsiMarkup.Escape(userText);
Try / catch
try { AnsiMarkup.Write(text); }
catch (InvalidOperationException ex) when (ex.Message.Contains("unescaped ']'"))
{ AnsiMarkup.Write(AnsiMarkup.Escape(text)); } Prevention
- Never interpolate raw data into markup; always run it through AnsiMarkup.Escape
- Remember `]` is the dangerous char (must be `]]`), more so than `[`
- Treat markup strings like a DSL, not a format string
When it happens
Trigger: Markup text containing a single `]`, e.g. `"array[0]"`, `"a]b"`, or a trailing `]` at end of string. Note `[` alone in text is fine (it just breaks the text run); `]` is the one that must be doubled.
Common situations: Rendering user-typed or data-driven text that contains array indexing, regex, or JSON snippets without escaping; markdown/CSV content spliced into markup.
Related errors
- Encountered closing tag when none was expected near position
- Encountered unknown markup token.
- Unbalanced markup stack. Did you forget to close a tag?
- Encountered malformed markup tag at position {pos}.
- A link has already been set.
AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13).
Data as JSON: /api/errors/c14da017bf50a204.
Report an issue: GitHub.