dianping/cat · error · SyntaxError

Expected {name} at line {line}, col {col}.

Error message

Expected {name} at line {line}, col {col}.

What it means

Thrown by the CSS worker's `TokenStream.mustMatch(tokenTypes)` when the next token(s) do not match a token type the grammar requires (selector colon, semicolon, closing brace, etc.). `mustMatch` is the parser's assertion operator: after the failed match it reads the actual lookahead token (`LT(1)`) and throws a `SyntaxError` naming the expected token type and the actual token's position. It means the statement was structurally incomplete or malformed at that point.

Source

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

        while(i < len){
            if (tt == tokenTypes[i++]){
                return true;
            }
        }
        this.unget();
        return false;
    },
    mustMatch: function(tokenTypes, channel){

        var token;
        if (!(tokenTypes instanceof Array)){
            tokenTypes = [tokenTypes];
        }

        if (!this.match.apply(this, arguments)){
            token = this.LT(1);
            throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
                " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
        }
    },
    advance: function(tokenTypes, channel){

        while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
            this.get();
        }

        return this.LA(0);
    },
    get: function(channel){

        var tokenInfo   = this._tokenData,
            reader      = this._reader,
            value,
            i           =0,
            len         = tokenInfo.length,

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Go to the line/col in the message and add the token named as 'Expected {name}' (e.g. insert the missing `;`, `:`, `{`, `}` or `)`).
  2. Look backwards from the reported position — the real mistake is usually an unterminated earlier rule (missing `}` or `;`) that shifted the parser onto the wrong token.
  3. Run the stylesheet through CSSLint/stylelint to get all mustMatch failures at once instead of fixing one per parse.
  4. If the CSS is machine-generated, fix the generator rather than patching output.

Example fix

/* before */
.menu { color: red }
.footer { color: blue; } /* mustMatch(RBRACE/SEMICOLON) may fire on malformed earlier rules */

/* after */
.menu { color: red; }
.footer { color: blue; }
Defensive patterns

Strategy: try-catch

Validate before calling

function quickSanity(css) {
  var depth = 0;
  for (var i = 0; i < css.length; i++) {
    if (css[i] === '{') depth++;
    if (css[i] === '}') depth--;
    if (depth < 0) return 'unexpected } at index ' + i;
  }
  return depth === 0 ? null : 'missing ' + depth + ' closing brace(s)';
}

Try / catch

try {
  parser.parse(css);
} catch (ex) {
  if (ex.line && ex.col) { jumpTo(ex.line, ex.col, ex.message); return; } // SyntaxError carries position
  throw ex;
}

Prevention

When it happens

Trigger: CSS missing a mandatory token: a declaration without a semicolon before `}` (`a{color:red}`), a media query missing `{`, `@import` without a following string/URL token, a selector missing its block. Any call like `tokenStream.mustMatch(Tokens.SEMICOLON)` / `mustMatch(Tokens.RBRACE)` / `mustMatch(Tokens.COLON)` where the input has something else (or EOF) next.

Common situations: Hand-typing CSS and forgetting `;` or `{}`; minifiers with bugs that drop trailing semicolons inside the wrong block; template literals that interpolate `undefined` leaving a hole where a token was expected; nested preprocessor output with an unclosed block.

Related errors


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