Common causes
1. A rule missing its closing brace
Here .card is never closed, so .card-title becomes a nested rule inside it (valid in modern CSS) and the brace meant for .card-title closes it instead. Everything after is one level too deep.
.card {
padding: 16px;
.card-title {
font-weight: 600;
}.card {
padding: 16px;
}
.card-title {
font-weight: 600;
}2. An @media or @supports block that is never closed
Media queries wrap other rules, so they need their own closing brace after the last inner rule. It is easy to close the inner rule and forget the outer one.
@media (max-width: 600px) {
.card { padding: 8px; }@media (max-width: 600px) {
.card { padding: 8px; }
}3. A doubled opening brace
A typo such as {{, often from template syntax, opens two blocks and closes only one.
.alert {{ color: #b00020; }.alert { color: #b00020; }4. An unclosed string or comment swallowing a brace
In content: "→; the string never ends, so the } after it is part of the string. PostCSS usually reports “Unclosed string” or “Unclosed comment” first; fix that and the block closes again.
.arrow::after { content: "→; }.arrow::after { content: "→"; }Frequently asked questions
Why does the error point at the last line or the first line?
The parser only knows a block is unclosed when the file ends. Depending on the tool, it reports the end of the file or the position where the open block started, neither of which is necessarily where the brace is missing.
Can nested CSS hide a missing brace?
Yes. Since native CSS nesting, a rule inside an unclosed rule is valid syntax, so the stylesheet may even partly work. Selectors then match only inside the parent, which shows up as styles that silently stopped applying.
Is the fix different in SCSS or Less?
No. Sass and Less use the same braces and report the same problem as expected “}” or missing closing }. PasteKit has SCSS and Less formatters that point at the open block.