dianping/cat · error · SyntaxError
@charset not allowed here.
Error message
@charset not allowed here.
What it means
Thrown when `@charset` appears at a position in the stylesheet where it is illegal — it must be the very first statement (only `@charset` may precede it, nothing else). The parser's default branch first tries `_ruleset()`; if that fails and the token is `CHARSET_SYM`, it consumes the rule (so parsing can continue) and then throws `SyntaxError('@charset not allowed here.')` at the `@charset` token's position. In non-strict mode this is caught and fired as an 'error' event instead of aborting.
Source
Thrown at cat-home/src/main/webapp/assets/js/editor/worker-css.js:2061
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);
this._namespace(false);
throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
default:
tokenStream.get(); //get the last token
this._unexpectedToken(tokenStream.token());
}
}
}
} catch(ex) {
if (ex instanceof SyntaxError && !this.options.strict){
this.fire({View on GitHub (pinned to e815e74d4c)
Solutions
- Move the single `@charset "utf-8";` to the absolute top of the file, before any rules, comments with rules, or `@import`.
- If you concatenate or inline CSS, strip all `@charset` statements except (optionally) one at the head of the output.
- Serve the stylesheet as UTF-8 with the right HTTP `Content-Type`/BOM and delete `@charset` entirely — it is rarely needed.
- Keep the parser in non-strict mode and surface the fired error event so users see the position instead of a thrown crash.
Example fix
/* before */
:root { --x: 1; }
@charset "utf-8"; /* @charset not allowed here. */
/* after */
@charset "utf-8";
:root { --x: 1; } Defensive patterns
Strategy: validation
Validate before calling
function charsetOk(css) {
var first = css.replace(/^(\s|\/\*[\s\S]*?\*\/\s*)*/, '');
var count = (css.match(/@charset\b/g) || []).length;
return count === 0 || (count === 1 && /^@charset/.test(first));
} Try / catch
try {
parser.parse(css);
} catch (ex) {
if (/@charset not allowed/.test(ex.message)) { css = css.replace(/@charset[^;]+;?\s*/g, ''); parser.parse(css); return; }
throw ex;
} Prevention
- Put @charset at byte 0 or drop it and rely on HTTP charset headers.
- Strip @charset from all concatenated fragments in build tooling.
- Lint at-rule ordering (@charset → @import → @namespace → rules) in CI.
When it happens
Trigger: `@charset "utf-8";` placed after any rule, selector block, `@import`, comment-with-rules, or anywhere other than byte-position 0 of the stylesheet; concatenating files where a later fragment contains its own `@charset`; feeding the parser a stylesheet fragment that retains an inner `@charset`.
Common situations: Build tools concatenating many CSS files without stripping their individual `@charset` lines; `@import` inlining that leaves the imported file's `@charset` mid-stream; developers pasting a boilerplate header below existing rules.
Related errors
- Unknown @ rule.
- @import not allowed here.
- @namespace not allowed here.
- Expected "{pattern}" at line {line}, col {col}.
- Expected {name} at line {line}, col {col}.
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/3eed6811ea2286a7.
Report an issue: GitHub.