{"record":{"id":"c14da017bf50a204","repo":"spectreconsole/spectre.console","slug":"encountered-unescaped-token-at-position-read","errorCode":null,"errorMessage":"Encountered unescaped ']' token at position {_reader.Position}","messagePattern":"Encountered unescaped '\\]' token at position (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Spectre.Console.Ansi/AnsiMarkup.cs","lineNumber":333,"sourceCode":"        var position = _reader.Position;\n        var builder = new StringBuilder();\n\n        while (!_reader.Eof)\n        {\n            var current = _reader.Peek();\n            if (current == '[')\n            {\n                // markup encountered. Stop processing.\n                break;\n            }\n\n            // If we find a closing tag (']') there must be two of them.\n            if (current == ']')\n            {\n                _reader.Read();\n                if (_reader.Peek() != ']')\n                {\n                    throw new InvalidOperationException(\n                        $\"Encountered unescaped ']' token at position {_reader.Position}\");\n                }\n            }\n\n            builder.Append(_reader.Read());\n        }\n\n        return new MarkupToken(MarkupTokenKind.Text, builder.ToString(), position);\n    }\n\n    private MarkupToken ReadMarkup()\n    {\n        var position = _reader.Position;\n\n        // Read initial opening bracket\n        _reader.Read();\n\n        if (_reader.Eof)","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/spectreconsole/spectre.console/blob/0acc92fada6c42f13984e79c2b5f3d993bdfb099/src/Spectre.Console.Ansi/AnsiMarkup.cs#L315-L351","documentation":"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.","triggerScenarios":"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.","commonSituations":"Rendering user-typed or data-driven text that contains array indexing, regex, or JSON snippets without escaping; markdown/CSV content spliced into markup.","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"],"exampleFix":"// before\nAnsiMarkup.Write($\"Result: {userText}\"); // breaks if userText contains ']'\n\n// after\nAnsiMarkup.Write($\"Result: {AnsiMarkup.Escape(userText)}\");","handlingStrategy":"validation","validationCode":"// Escape dynamic text before embedding; this is the canonical prevention:\nvar safe = AnsiMarkup.Escape(userText);","typeGuard":null,"tryCatchPattern":"try { AnsiMarkup.Write(text); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"unescaped ']'\"))\n{ AnsiMarkup.Write(AnsiMarkup.Escape(text)); }","preventionTips":["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"],"tags":["markup","parsing","escaping","spectre-console"],"backgroundTag":null,"analyzedSha":"0acc92fada6c42f13984e79c2b5f3d993bdfb099","analyzedAt":"2026-08-13T18:27:21.983Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}