swc-project/swc · error · Error

Unexpected character in hex color

Error message

Unexpected character in hex color

What it means

Thrown by Parse<HexColor> in swc_css_parser when the token is a hash but its value contains characters outside [0-9a-fA-F]. After bumping Token::Hash it validates every char with is_ascii_hexdigit(); idents-as-hashes such as '#gg', '#ff00zz', or '#red' (r is not a hex digit) fail with the span of the whole hash token. Note the parser does not enforce 3/4/6/8 digit lengths here - only the character set.

Source

Thrown at crates/swc_css_parser/src/parser/values_and_units/mod.rs:2434

        }
    }
}

impl<I> Parse<HexColor> for Parser<I>
where
    I: ParserInput,
{
    fn parse(&mut self) -> PResult<HexColor> {
        let span = self.input.cur_span();

        if !is!(self, "#") {
            return Err(Error::new(span, ErrorKind::Expected("hash token")));
        }

        match bump!(self) {
            Token::Hash { value, raw, .. } => {
                if value.chars().any(|x| !x.is_ascii_hexdigit()) {
                    return Err(Error::new(
                        span,
                        ErrorKind::Unexpected("character in hex color"),
                    ));
                }

                Ok(HexColor {
                    span,
                    value,
                    raw: Some(raw),
                })
            }
            _ => {
                unreachable!()
            }
        }
    }
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Fix the hex digits: '#gg' -> '#ccc'-style valid hex; only 0-9 and a-f characters.
  2. If the string is an id/anchor ('#main'), it is not a color; move it out of the color grammar.
  3. Validate hex bodies with ^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$ before parsing.

Example fix

/* before */
a { color: #ff00zz; }

/* after */
a { color: #ff00aa; }
Defensive patterns

Strategy: validation

Validate before calling

const HEX = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
function isValidHexColor(v: string): boolean {
  return HEX.test(v.trim());
}

Type guard

fn is_valid_hex_color(v: &str) -> bool {
    let b = v.as_bytes();
    matches!(b.len(), 4 | 5 | 7 | 9)
        && b[0] == b'#'
        && b[1..].iter().all(|c| c.is_ascii_hexdigit())
}

Try / catch

use swc_css_parser::error::ErrorKind;
if let Err(e) = parse_input::<Stylesheet>(src, opts) {
    if matches!(e.kind(), ErrorKind::Unexpected("character in hex color")) {
        return Err(format!("bad hex digits at {:?}", e.span()).into());
    }
    return Err(e.into());
}

Prevention

When it happens

Trigger: Values like 'color: #gg', 'color: #ff00zz', 'color: #0f0f0g', or CSS-module class selectors mistakenly parsed as colors ('#.side' style content in a color slot).

Common situations: Hash-prefixed identifiers mistaken for colors (e.g. '#main'), color strings with g-z characters from bad copy-paste, and hand-rolled color shorteners corrupting hex digits.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/81b1e1d14a96581e. Report an issue: GitHub.