{"record":{"id":"2f0db993417ace9e","repo":"Textualize/textual","slug":"unexpected-end-of-file-did-you-forget-a-u","errorCode":null,"errorMessage":"Unexpected end of file; did you forget a '}' ? / Unexpected end of text","messagePattern":"Unexpected end of file; did you forget a '\\}' \\? / Unexpected end of text","errorType":"exception","errorClass":"UnexpectedEnd","httpStatus":null,"severity":"error","filePath":"src/textual/css/tokenizer.py","lineNumber":254,"sourceCode":"\n        Returns:\n            A new Token.\n        \"\"\"\n\n        line_no = self.line_no\n        col_no = self.col_no\n        if line_no >= len(self.lines):\n            if expect._expect_eof:\n                return Token(\n                    \"eof\",\n                    \"\",\n                    self.read_from,\n                    self.code,\n                    (line_no, col_no),\n                    None,\n                )\n            else:\n                raise UnexpectedEnd(\n                    self.read_from,\n                    self.code,\n                    (line_no + 1, col_no + 1),\n                    (\n                        \"Unexpected end of file; did you forget a '}' ?\"\n                        if expect._expect_semicolon\n                        else \"Unexpected end of text\"\n                    ),\n                )\n        line = self.lines[line_no]\n        preceding_text: str = \"\"\n        if expect._extract_text:\n            match = expect.search(line, col_no)\n            if match is None:\n                preceding_text = line[self.col_no :]\n                self.line_no += 1\n                self.col_no = 0\n            else:","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/css/tokenizer.py#L236-L272","documentation":"UnexpectedEnd is a TokenError raised by the tokenizer when input ends while still expecting tokens — with the hint about a missing '}' when the last expectation was a declaration expecting a semicolon, or 'Unexpected end of text' otherwise.","triggerScenarios":"Tokenizing CSS that ends mid-declaration or with unclosed braces, e.g. '#box { width: 10' or '$Button { color: red' with no closing brace before EOF.","commonSituations":"Truncated CSS files, copy-paste losing the final brace, or programmatically concatenated CSS strings missing terminators.","solutions":["Add the missing '}' to close every rule block","Terminate every declaration with ';'","Check the reported line/column — it points at/after the last valid token"],"exampleFix":"/* before */\n#box { color: red;\n/* after */\n#box { color: red; }","handlingStrategy":"validation","validationCode":"def braces_balanced(css: str) -> bool:\n    depth = 0\n    for ch in css:\n        if ch == '{': depth += 1\n        elif ch == '}': depth -= 1\n        if depth < 0: return False\n    return depth == 0","typeGuard":null,"tryCatchPattern":"from textual.css.tokenizer import UnexpectedEnd\ntry:\n    stylesheet.parse()\nexcept UnexpectedEnd as e:\n    report(f\"unbalanced CSS near line {e.location[0]}: {e}\")","preventionTips":["Check that every '{' has a matching '}'","Terminate declarations with ';'","Brace-count CSS before parsing programmatically built strings"],"tags":["textual","css","tokenizer","unexpected-end"],"backgroundTag":"unexpected-end-of-input","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}