Skip to content

Color.FromHex accepts "#+F+F+F" as #0F0F0F and throws FormatException (not ArgumentException) for non-hex characters #313

Description

@matt-edmondson

What's wrong

Semantics.Color/Color.Conversions.cs FromHex (L49-L70) checks only the string's length, then parses each channel with ParseByte (L99-L100): Convert.ToByte(hex.Substring(index, 2), 16). Convert.ToByte(string, 16) has two quirks that leak through:

  • A leading + is accepted, so Color.FromHex("#+F+F+F").ToHex() returns "#0F0F0F" and invalid input is accepted without complaint. The same applies to "+F" inside any 6- or 8-digit string.
  • A non-hex character throws FormatException, so FromHex("#GGGGGG") and FromHex("#0x0x0x") both throw it. FromHex("#-1-1-1") throws ArgumentException instead. The exception type therefore depends on which bad character appears.

The XML docs for FromHex list only ArgumentNullException and ArgumentException, and CLAUDE.md says to throw ArgumentException for validation failures, not FormatException. A caller that validates user or theme input with catch (ArgumentException) crashes on #GGGGGG and silently accepts #+F+F+F.

All of these were reproduced by compiling Semantics.Color into a scratch console app.

Suggested fix

  • After length normalisation, check that every character is [0-9A-Fa-f], and throw ArgumentException(..., nameof(hex)) if one is not.
  • Parse each channel with byte.Parse(span, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture), which rejects signs.
  • Add tests: #+F+F+F, #GGGGGG, #0x0x0x and #-1-1-1 all throw ArgumentException, and valid 3/6/8-digit inputs in either case still round-trip.

Activity

  1. matt-edmondson commented on Sep 28, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    Notes: byte.Parse(span, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture) plus an explicit character check is a small fix. The listed test cases cover every path.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions