roboflow/supervision · error · ValueError
Invalid characters in color hash
Error message
Invalid characters in color hash
What it means
Raised by _validate_color_hex when a hex color string contains characters outside [0-9a-fA-F] after stripping an optional leading '#'. All Color.from_hex_color() / palette parsing goes through this validator. It guards the subsequent length check (3/4/6/8 digits) and the int(hex, 16) parse from garbage input like 'GGG' or '#12G45F'.
Source
Thrown at src/supervision/draw/color.py:58
"#46F0F0",
"#F032E6",
"#D2F53C",
"#FABEBE",
"#008080",
"#E6BEFF",
"#AA6E28",
"#FFFAC8",
"#800000",
"#AAFFC3",
]
ROBOFLOW_COLOR_PALETTE = ["C28DFC", "A351FB", "8315F9", "6706CE", "5905B3", "4D049A"]
def _validate_color_hex(color_hex: str) -> None:
color_hex = color_hex.lstrip("#")
if not all(c in "0123456789abcdefABCDEF" for c in color_hex):
raise ValueError("Invalid characters in color hash")
if len(color_hex) not in (3, 4, 6, 8):
raise ValueError("Invalid length of color hash")
@dataclass
class Color:
"""
Represents a color in RGBA format.
This class provides methods to work with colors, including creating colors from hex
codes, converting colors to hex strings, RGB tuples, BGR tuples, RGBA tuples,
and BGRA tuples.
Attributes:
r: Red channel value (0-255).
g: Green channel value (0-255).
b: Blue channel value (0-255).
a: Alpha channel value (0-255). Default is 255 (fully opaque).View on GitHub (pinned to 7f254d9784)
Solutions
- Normalize input before use: strip whitespace, allow only one leading '#', then validate with a regex like ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
- Convert named/CSS colors to hex first (e.g. matplotlib.colors.to_hex)
- Pre-validate UI color pickers to emit hex only
Example fix
# before
color = Color.from_hex_color('#ff00gg') # 'g' is not a hex digit
# after
import re
if not re.fullmatch(r'#?[0-9a-fA-F]{3,4}|#?[0-9a-fA-F]{6}|#?[0-9a-fA-F]{8}', value):
raise ValueError(f'Not a hex color: {value!r}')
color = Color.from_hex_color(value.lower()) Defensive patterns
Strategy: validation
Validate before calling
import re
HEX_RE = re.compile(r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$')
def normalize_hex(value: str) -> str:
value = value.strip()
if not HEX_RE.fullmatch(value):
raise ValueError(f'not a hex color: {value!r}')
return value
color = Color.from_hex_color(normalize_hex(user_input)) Type guard
import re
HEX_COLOR_RE = re.compile(r'#?(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})')
def is_hex_color(value: object) -> bool:
"""True when value is a valid 3/4/6/8-digit hex color string."""
return isinstance(value, str) and HEX_COLOR_RE.fullmatch(value) is not None Try / catch
try:
color = Color.from_hex_color(theme_color)
except ValueError as e:
if 'color hash' in str(e):
color = Color.WHITE # safe default, log the bad value
else:
raise Prevention
- Constrain color pickers and config schemas to hex strings
- Convert named/CSS colors with matplotlib.colors.to_hex before passing to supervision
When it happens
Trigger: Calling Color.from_hex_color('xyz123'), passing a CSS rgb() string, including the '#' twice ('##ff0000' — the second '#' fails the character test), or typos like '#ff00gg'.
Common situations: User-supplied theme colors from a config/UI field without validation; colors copied with stray characters; abbreviations like 'rgb(255,0,0)' or named colors ('red') passed where hex is expected.
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
- module {__name__} has no attribute {name}
- Edge indices must use the 1-based convention and be within t
- sigma must contain at least one value
- All sigma values must be positive
- max_axis must be positive when provided
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/d9aa68629c677794.
Report an issue: GitHub.