{"record":{"id":"a8b40a9aab9ad1b3","repo":"python/cpython","slug":"unexpected-char-in-declaration","errorCode":null,"errorMessage":"unexpected '[' char in declaration","messagePattern":"unexpected '\\[' char in declaration","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Lib/_markupbase.py","lineNumber":132,"sourceCode":"                if not m:\n                    return -1 # incomplete\n                j = m.end()\n            elif c in \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\":\n                name, j = self._scan_name(j, i)\n            elif c in self._decl_otherchars:\n                j = j + 1\n            elif c == \"[\":\n                # this could be handled in a separate doctype parser\n                if decltype == \"doctype\":\n                    j = self._parse_doctype_subset(j + 1, i)\n                elif decltype in {\"attlist\", \"linktype\", \"link\", \"element\"}:\n                    # must tolerate []'d groups in a content model in an element declaration\n                    # also in data attribute specifications of attlist declaration\n                    # also link type declaration subsets in linktype declarations\n                    # also link attribute specification lists in link declarations\n                    raise AssertionError(\"unsupported '[' char in %s declaration\" % decltype)\n                else:\n                    raise AssertionError(\"unexpected '[' char in declaration\")\n            else:\n                raise AssertionError(\"unexpected %r char in declaration\" % rawdata[j])\n            if j < 0:\n                return j\n        return -1 # incomplete\n\n    # Internal -- parse a marked section\n    # Override this to handle MS-word extension syntax <![if word]>content<![endif]>\n    def parse_marked_section(self, i, report=1):\n        rawdata= self.rawdata\n        assert rawdata[i:i+3] == '<![', \"unexpected call to parse_marked_section()\"\n        sectName, j = self._scan_name( i+3, i )\n        if j < 0:\n            return j\n        if sectName in {\"temp\", \"cdata\", \"ignore\", \"include\", \"rcdata\"}:\n            # look for standard ]]> ending\n            match= _markedsectionclose.search(rawdata, i+3)\n        elif sectName in {\"if\", \"else\", \"endif\"}:","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_markupbase.py#L114-L150","documentation":"AssertionError raised by _markupbase.ParserBase._scan_decl when a '[' appears inside a declaration whose type is not doctype, attlist, linktype, link, or element. It mirrors the sibling 'unsupported' error but fires for unrecognized declaration keywords, e.g. an internal-subset-only construct appearing at top level where the scanner cannot dispatch it.","triggerScenarios":"HTMLParser.feed() on markup like <![ ... ]> handled outside parse_marked_section paths, or <!FOO [ ... ]> where FOO is an unknown declaration keyword containing '['. Any '<!' construct whose scanned name is none of the known types and whose body contains '['.","commonSituations":"Parsing malformed or machine-generated HTML; conditional-comment-like or MS Office markup fragments reaching the declaration scanner; concatenating fragments so a '<![' begins mid-stream after another declaration's name.","solutions":["Sanitize input: remove unknown '<!...>' blocks before feeding the parser.","Wrap feed() in try/except AssertionError and resume after the closing '>' of the bad construct (find it with rawdata.find('>')).","For conditional comments <![if ...]>, subclass HTMLParser and override parse_marked_section / unknown_decl instead of letting the base scanner see them.","Validate markup with a tolerant library (bleach, html5lib) if input provenance is untrusted."],"exampleFix":"# before\nHTMLParser().feed('<!custom [ data ]>')  # AssertionError: unexpected '[' char in declaration\n\n# after\nimport re\nfeed = re.sub(r'<![!\\w-]*\\s*\\[.*?\\]?>?', '', raw)  # strip bracketed decls\nHTMLParser().feed(feed)","handlingStrategy":"try-catch","validationCode":"import re\n_DECL_OK = re.compile(r'<!\\s*(doctype|element|attlist|entity|notation)\\b[^\\[]*>', re.I)\n\ndef declarations_ok(raw: str) -> bool:\n    return all(_DECL_OK.match(d) or '[' not in d for d in re.findall(r'<![^>]*>', raw))","typeGuard":null,"tryCatchPattern":"try:\n    parser.feed(data)\nexcept AssertionError as e:\n    if 'declaration' in str(e):\n        bad = data.rfind('<!', 0, parser.offset + 1)\n        data = data[:bad] + data[data.find('>', bad) + 1:]\n        parser.reset(); parser.feed(data)\n    else:\n        raise","preventionTips":["Sanitize untrusted '<!' constructs before parsing.","Keep html.parser input to real HTML; route SGML-ish data to SGML tools.","Wrap feed() centrally so one bad declaration cannot kill the pipeline."],"tags":["markup","html-parser","parsing","malformed-html"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}