dotnet/wpf · error · FormatException

SR.Parser_UnexpectedToken

Error message

SR.Parser_UnexpectedToken

What it means

ThrowBadToken is the shared failure routine of the path mini-language tokenizer (the class wrapping the geometry string). Whenever SkipWhiteSpace, IsNumber, ReadNumber, ReadBool, or ParseToGeometryContext encounters a character that cannot start a valid token in the current position, it calls ThrowBadToken, which throws FormatException with SR.Parser_UnexpectedToken including the offending path string and the character index.

Solutions

  1. Inspect the exception message: it names the path string and the offending index; fix the character at that position.
  2. Use only WPF mini-language commands: M/m, L/l, H/h, V/v, C/c, Q/q, S/s, T/t, A/a, Z/z, with F0/F1 optionally at the start.
  3. Remove characters not in the mini-language (semicolons, parentheses, unit suffixes like 'px').
  4. Wrap parsing in try-catch for FormatException and fall back to a safe geometry.

Example fix

// before
geo = StreamGeometry.Parse("M 0,0 X 5,5"); // 'X' is not a command -> throws

// after
geo = StreamGeometry.Parse("M 0,0 L 5,5"); // valid line command
Defensive patterns

Strategy: try-catch

Validate before calling

static readonly Regex AllowedChars = new Regex("^[MmLlHhVvCcQqSsTtAaZzFf0-9,.eE+\-\s]*$");
static bool HasOnlyMiniLanguageChars(string path) => path != null && AllowedChars.IsMatch(path);

Try / catch

try { return StreamGeometry.Parse(data); }
catch (FormatException ex)
{
    // message contains the offending path and index
    log.Warn(ex, "Unexpected token in path data");
    return Geometry.Empty;
}

Prevention

When it happens

Trigger: StreamGeometry.Parse / Geometry.Parse / Path.Data with a character where a command letter or number is expected — e.g. 'M0,0;L10,10' (semicolon), 'M 0,0 X 5,5' (unknown command X), or a stray letter/number in an unexpected slot like 'M0,,0'.

Common situations: Typos in hand-written XAML Data attributes; pasted SVG data containing unsupported commands (arcs with flags in different order is fine, but e.g. lowercase-disallowed contexts or 'H/V' misuse handled elsewhere); generated strings with separators WPF does not accept.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/406c24e85b5bcbbe. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/ParsersCommon.cs:195

        private string          _pathString;        // Input string to be parsed
        private int             _pathLength;
        private int             _curIndex;          // Location to read next character from 
        private bool            _figureStarted;     // StartFigure is effective
        
        private Point           _lastStart;         // Last figure starting point
        private Point           _lastPoint;         // Last point
        private Point           _secondLastPoint;   // The point before last point
        
        private char            _token;             // Non whitespace character returned by ReadToken

        private StreamGeometryContext _context;
        
        /// <summary>
        /// Throw unexpected token exception
        /// </summary>
        private void ThrowBadToken()
        {
            throw new System.FormatException(SR.Format(SR.Parser_UnexpectedToken, _pathString, _curIndex - 1));
        }

        private bool More()
        {
            return _curIndex < _pathLength;
        }
        
        // Skip white space, one comma if allowed
        private bool SkipWhiteSpace(bool allowComma)
        {
            bool commaMet = false;
            
            while (More())
            {
                char ch = _pathString[_curIndex];
                
                switch (ch)
                {

View on GitHub (pinned to 81131a70a4)