swc-project/swc · error · swc_css_parser::error::Error

Unexpected end of file

Error message

Unexpected end of file

What it means

Input::cur() was called on the token-stream input when the parser has already consumed every token: the position stack ('idx') is empty, so there is no current token to return. The parser surfaces this as an unexpected-EOF error positioned at the end of input. It almost always means the grammar expected more input (a closing brace, paren, or value) but the stylesheet ended.

Source

Thrown at crates/swc_css_parser/src/parser/input.rs:359

                res
            }
            None => return None,
            _ => {
                unreachable!("Not allowed in the list of component values")
            }
        }
    }

    fn cur(&mut self) -> PResult<Cow<'_, TokenAndSpan>> {
        match self.input {
            InputType::Tokens(input) => {
                let idx = match self.idx.last() {
                    Some(idx) => idx,
                    _ => {
                        let bp = input.span.hi;
                        let span = Span::new(bp, bp);

                        return Err(Error::new(span, ErrorKind::Eof));
                    }
                };

                let token_and_span = match input.tokens.get(*idx) {
                    Some(token_and_span) => token_and_span,
                    None => {
                        let bp = input.span.hi;
                        let span = Span::new(bp, bp);

                        return Err(Error::new(span, ErrorKind::Eof));
                    }
                };

                Ok(Cow::Borrowed(token_and_span))
            }
            InputType::ListOfComponentValues(input) => {
                let token_and_span = match self.get_component_value(&input.children, 0) {
                    Some(token_or_block) => match token_or_block {

View on GitHub (pinned to 5176682b65)

Solutions

  1. Balance delimiters: every '{', '(', '[' closed, strings and comments terminated
  2. If parsing a fragment, wrap or repair it (append the missing closers) before parsing
  3. For streams, buffer until the stylesheet is complete instead of parsing partial input
  4. Locate the innermost unclosed construct by counting delimiters from the start of input

Example fix

/* before */
.a { color: red;
/* after */
.a { color: red; }
Defensive patterns

Strategy: validation

Validate before calling

// Reject obviously unbalanced/truncated stylesheets before parsing
function isBalanced(css) {
  const pairs = { '{': '}', '(': ')', '[': ']' };
  const stack = [];
  for (const ch of css.replace(/\./g, '').replace(/"[^"]*"|'[^']*'|\/\*[\s\S]*?\*\//g, '')) {
    if (pairs[ch]) stack.push(ch);
    else if (Object.values(pairs).includes(ch)) { if (pairs[stack.pop()] !== ch) return false; }
  }
  return stack.length === 0;
}

Try / catch

// JS
try { parse(css, opts); } catch (e) { if (/end of file/.test(e.message)) requestMoreInputOrAppendClosers(css); }

Prevention

When it happens

Trigger: Unclosed '{' (rule block), '(' (media query or declaration value), unclosed string/comment, or a truncated file: '.a { color: red;' or '@media (width { ... }' reaching end of input while the parser still asks for the next token.

Common situations: Incremental/streaming pipelines that feed partial buffers to the parser; files truncated by a failed write or an interrupted network transfer; user-authored CSS in CMS fields where the closing brace was never typed; code that re-parses fragments without balancing delimiters first.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/12ad420779dbf2b3. Report an issue: GitHub.