{"record":{"id":"1e6be281e551ccc9","repo":"swc-project/swc","slug":"comma-token","errorCode":null,"errorMessage":"comma token","messagePattern":"comma token","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/swc_css_parser/src/parser/values_and_units/mod.rs","lineNumber":505,"sourceCode":"                            &mut has_variable,\n                        )?;\n\n                        if let Some(hue_or_none) = hue_or_none {\n                            values.push(hue_or_none);\n                        }\n\n                        self.input.skip_ws();\n                    }\n                    _ => {\n                        unreachable!()\n                    }\n                }\n\n                if is!(self, \",\") {\n                    if !is_legacy_syntax && !has_variable {\n                        let span = self.input.cur_span();\n\n                        return Err(Error::new(span, ErrorKind::Expected(\"comma token\")));\n                    }\n\n                    is_legacy_syntax = true;\n\n                    values.push(ComponentValue::Delimiter(self.parse()?));\n\n                    self.input.skip_ws();\n                } else {\n                    is_legacy_syntax = false;\n                }\n\n                match &*lower_fname {\n                    \"rgb\" | \"rgba\" => {\n                        let percentage_or_number = self.try_parse_variable_function(\n                            |parser, has_variable_before| match cur!(parser) {\n                                tok!(\"percentage\") => {\n                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))\n                                }","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_css_parser/src/parser/values_and_units/mod.rs#L487-L523","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Remove the comma the error span points at; modern syntax separates channels with whitespace and alpha with '/'.","If you need 'none' plus commas, that combination is invalid by spec — use space syntax or omit 'none'.","When var() is involved anywhere in the function the parser tolerates the comma; prefer fixing the literal CSS rather than leaning on that."],"exampleFix":"/* before */\ncolor: rgb(none, 0, 0);\ncolor: rgb(from red, 255, 0, 0);\n\n/* after */\ncolor: rgb(none 0 0);\ncolor: rgb(from red r g b);","handlingStrategy":"try-catch","validationCode":"fn consistent_separators(args: &str) -> bool {\n    let has_comma = args.contains(',');\n    let has_space_sep = args\n        .split(|c: char| c == ',' || c == '/')\n        .any(|seg| seg.trim().split_whitespace().count() > 1);\n    !(has_comma && has_space_sep) // mixing comma and space separation is always invalid\n}","typeGuard":"fn is_modern_color_fn(text: &str) -> bool {\n    // 'none' channels or 'from' keyword force modern (space) syntax: commas then fail\n    let t = text.to_ascii_lowercase();\n    (t.contains(\"none\") || t.contains(\"from\")) && t.contains(',')\n}","tryCatchPattern":"if let Err(err) = swc_css_parser::parse_string::<Stylesheet>(css, config) {\n    if matches!(&err.kind(), ErrorKind::Expected(m) if m == \"comma token\") {\n        let (span, _) = err.into_inner();\n        // a comma appeared inside a modern (space-separated / from / none) rgb-hsl function; strip it at span\n    }\n    return Err(err.into());\n}","preventionTips":["Pick one notation per rule: all commas (legacy) or all spaces with '/' alpha (modern).","Remember 'none' channels and 'from' relative colors are modern-only — never combine them with commas.","Run stylelint's color-function-notation rule in CI to catch mixed separators before the parser does."],"tags":["css","swc","css-parser","rgb","hsl","comma","mixed-syntax"],"backgroundTag":"css-color-function-mixed-syntax","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}