Textualize/textual · error · UnexpectedEnd

Unexpected end of file; did you forget a '}' ? / Unexpected

Error message

Unexpected end of file; did you forget a '}' ? / Unexpected end of markup

What it means

UnexpectedEnd raised by Tokenizer.skip_to when scanning forward (e.g. to the end of a block or declaration list) hits the end of input. Message hints at a missing '}' when a semicolon was expected, else 'Unexpected end of markup'.

Source

Thrown at src/textual/css/tokenizer.py:365

    def skip_to(self, expect: Expect) -> Token:
        """Skip tokens.

        Args:
            expect: Expect object describing the expected token.

        Raises:
            UnexpectedEndOfText: If end of file is reached.

        Returns:
            A new token.
        """
        line_no = self.line_no
        col_no = self.col_no

        while True:
            if line_no >= len(self.lines):
                raise UnexpectedEnd(
                    self.read_from,
                    self.code,
                    (line_no, col_no),
                    (
                        "Unexpected end of file; did you forget a '}' ?"
                        if expect._expect_semicolon
                        else "Unexpected end of markup"
                    ),
                )
            line = self.lines[line_no]
            match = expect.search(line, col_no)

            if match is None:
                line_no += 1
                col_no = 0
            else:
                self.line_no = line_no
                self.col_no = match.span(0)[0]

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Close every '{' with a matching '}'
  2. Ensure declaration lists are terminated
  3. Validate CSS strings before passing them to Stylesheet by counting braces

Example fix

/* before */
Screen { layout: vertical;
/* after */
Screen { layout: vertical; }
Defensive patterns

Strategy: validation

Validate before calling

def css_terminators_ok(css: str) -> bool:
    css = css.strip()
    return css.endswith('}') and '{' not in css.split('}')[-1] and braces_balanced(css)

Try / catch

from textual.css.tokenizer import UnexpectedEnd
try:
    stylesheet.parse()
except UnexpectedEnd as e:
    report(f"missing '}}' near {e.location}: {e}")

Prevention

When it happens

Trigger: skip_to(',') or skip_to(';') on input where the terminator never appears — typically an unclosed rule block or a declaration list that runs to EOF without its closing brace/semicolon.

Common situations: Same class of issues as [106]: truncated or hand-written CSS missing the closing '}' — but surfacing through the skip-to recovery path rather than get_token's main loop.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/d356ef34db8bd77a. Report an issue: GitHub.