swc-project/swc · error · Error

comma token

Error message

comma token

What it means

swc_css_parser raises this when it sees a comma inside rgb()/rgba()/hsl()/hsla() while the function is in MODERN (space-separated) mode (crates/swc_css_parser/src/parser/values_and_units/mod.rs:501-506). is_legacy_syntax starts true but is flipped to false by the relative-color 'from' branch (line 384) or by an ident first channel such as 'none' (line 416); a comma in that state, with no var() present, returns ErrorKind::Expected("comma token") at the comma's span. The message reads 'Expected comma token' even though the comma is the offending input — it really means 'this comma is illegal here'.

Source

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

                            &mut has_variable,
                        )?;

                        if let Some(hue_or_none) = hue_or_none {
                            values.push(hue_or_none);
                        }

                        self.input.skip_ws();
                    }
                    _ => {
                        unreachable!()
                    }
                }

                if is!(self, ",") {
                    if !is_legacy_syntax && !has_variable {
                        let span = self.input.cur_span();

                        return Err(Error::new(span, ErrorKind::Expected("comma token")));
                    }

                    is_legacy_syntax = true;

                    values.push(ComponentValue::Delimiter(self.parse()?));

                    self.input.skip_ws();
                } else {
                    is_legacy_syntax = false;
                }

                match &*lower_fname {
                    "rgb" | "rgba" => {
                        let percentage_or_number = self.try_parse_variable_function(
                            |parser, has_variable_before| match cur!(parser) {
                                tok!("percentage") => {
                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
                                }

View on GitHub (pinned to 5176682b65)

Solutions

  1. Pick ONE separator style: fully modern 'rgb(none 0 0)' / 'rgb(255 0 0 / 50%)' or fully legacy 'rgb(0, 0, 0)' (legacy cannot use 'none' channels).
  2. Remove the comma the error span points at; modern syntax separates channels with whitespace and alpha with '/'.
  3. If you need 'none' plus commas, that combination is invalid by spec — use space syntax or omit 'none'.
  4. When var() is involved anywhere in the function the parser tolerates the comma; prefer fixing the literal CSS rather than leaning on that.

Example fix

/* before */
color: rgb(none, 0, 0);
color: rgb(from red, 255, 0, 0);

/* after */
color: rgb(none 0 0);
color: rgb(from red r g b);
Defensive patterns

Strategy: try-catch

Validate before calling

fn consistent_separators(args: &str) -> bool {
    let has_comma = args.contains(',');
    let has_space_sep = args
        .split(|c: char| c == ',' || c == '/')
        .any(|seg| seg.trim().split_whitespace().count() > 1);
    !(has_comma && has_space_sep) // mixing comma and space separation is always invalid
}

Type guard

fn is_modern_color_fn(text: &str) -> bool {
    // 'none' channels or 'from' keyword force modern (space) syntax: commas then fail
    let t = text.to_ascii_lowercase();
    (t.contains("none") || t.contains("from")) && t.contains(',')
}

Try / catch

if let Err(err) = swc_css_parser::parse_string::<Stylesheet>(css, config) {
    if matches!(&err.kind(), ErrorKind::Expected(m) if m == "comma token") {
        let (span, _) = err.into_inner();
        // a comma appeared inside a modern (space-separated / from / none) rgb-hsl function; strip it at span
    }
    return Err(err.into());
}

Prevention

When it happens

Trigger: parse_string on 'rgb(none, 0, 0)' (ident 'none' disables legacy mode, then comma at line 501 trips the check), 'rgb(from red, 255, 0, 0)' ('from' disables legacy mode), 'hsl(from red, 240, 50%)'. The guard '!is_legacy_syntax && !has_variable' at line 502 is what rejects the comma pushed at line 510.

Common situations: Hand-merging legacy comma syntax with CSS Color 4 features ('none', relative colors) during migrations; templates that always append commas; editing modern syntax output (e.g. from Chrome DevTools 'rgb(255 0 0 / 50%)') by adding commas back; CSS generators targeting old browsers but sprinkling in new keywords.

Related errors


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