dianping/cat · error · SyntaxError

Unknown @ rule.

Error message

Unknown @ rule.

What it means

Thrown by the CSS worker's stylesheet parser when it encounters an `@` token whose at-keyword is not one of the at-rules it implements (`@media`, `@page`, `@import`, `@charset`, `@namespace`, `@font-face`, `@keyframes`/vendor variants, `@supports`-era rules absent here). After the recognized cases fall through, the else branch throws `SyntaxError('Unknown @ rule.')` anchored at the at-token's position. It is a grammar-coverage failure: the CSS is (or may be) valid, but this parser build does not know the rule.

Source

Thrown at cat-home/src/main/webapp/assets/js/editor/worker-css.js:2049

                                    this.fire({
                                        type:       "error",
                                        error:      null,
                                        message:    "Unknown @ rule: " + tokenStream.LT(0).value + ".",
                                        line:       tokenStream.LT(0).startLine,
                                        col:        tokenStream.LT(0).startCol
                                    });
                                    count=0;
                                    while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
                                        count++;    //keep track of nesting depth
                                    }

                                    while(count){
                                        tokenStream.advance([Tokens.RBRACE]);
                                        count--;
                                    }

                                } else {
                                    throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
                                }
                                break;
                            case Tokens.S:
                                this._readWhitespace();
                                break;
                            default:
                                if(!this._ruleset()){
                                    switch(tt){
                                        case Tokens.CHARSET_SYM:
                                            token = tokenStream.LT(1);
                                            this._charset(false);
                                            throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
                                        case Tokens.IMPORT_SYM:
                                            token = tokenStream.LT(1);
                                            this._import(false);
                                            throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
                                        case Tokens.NAMESPACE_SYM:
                                            token = tokenStream.LT(1);

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Identify the at-rule at the reported position; if it was a typo (e.g. `@medi`), correct it to a real at-rule.
  2. If the rule is modern-but-valid (`@supports`, `@layer`, `@container`), move it into a file this parser does not validate, or upgrade/replace worker-css.js with a parser that supports it (postcss, css-tree).
  3. Strip preprocessor directives (`@mixin`, `@extend`) before handing compiled output to the worker — feed the compiled CSS, not the Sass source.
  4. Run in non-strict mode and subscribe to the parser's 'error' event so unknown at-rules are reported per-rule instead of aborting the whole parse.

Example fix

/* before */
@supports (display: grid) { .g { display: grid; } } /* parser: Unknown @ rule. */

/* after (option 1: rule this parser knows) */
@media (min-width: 0) { .g { display: block; } }
/* after (option 2): keep @supports and upgrade/swap the CSS parser */
Defensive patterns

Strategy: try-catch

Validate before calling

var KNOWN_AT = /^@(media|page|import|charset|namespace|font-face|(-moz|-o|-webkit|-ms-)?keyframes)\b/;
function preflightAtRules(css) {
  var unknown = [];
  (css.match(/@[\w-]+/g) || []).forEach(function (r) {
    if (!KNOWN_AT.test(r)) unknown.push(r);
  });
  return unknown; // e.g. ['@supports', '@layer'] -> route around this parser
}

Try / catch

try {
  parser.parse(css);
} catch (ex) {
  if (/Unknown @ rule/.test(ex.message)) { logWarn('skipping modern at-rule at ' + ex.line + ':' + ex.col); return; }
  throw ex;
}

Prevention

When it happens

Trigger: Stylesheets using at-rules newer or less common than the parser's set: `@supports`, `@document`, `@viewport`, `@counter-style`, `@font-feature-values`, `@layer`, `@container`, `@scope`; or a typo'd at-rule like `@medi (min-width:0)`. Parsing such input through this worker's `parse()`/`_stylesheet()` path.

Common situations: Modern CSS shipped to an older bundled worker-css.js (common in long-lived apps and CMS installs); CSS written for a preprocessor (`@extend`, `@mixin` from Sass) accidentally fed to the plain CSS parser; vendor-specific at-rules the token table lacks.

Related errors


AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14). Data as JSON: /api/errors/c67ffcc746b149fa. Report an issue: GitHub.