{"record":{"id":"b49eb35f4be4832c","repo":"python/cpython","slug":"unsupported-char-in-s-declaration","errorCode":null,"errorMessage":"unsupported '[' char in %s declaration","messagePattern":"unsupported '\\[' char in (.+?) declaration","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Lib/_markupbase.py","lineNumber":130,"sourceCode":"            if c in \"\\\"'\":\n                m = _declstringlit_match(rawdata, j)\n                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","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_markupbase.py#L112-L148","documentation":"AssertionError raised by _markupbase.ParserBase._scan_decl when a '[' character appears inside an <!ATTLIST, <!LINKTYPE, <!LINK, or <!ELEMENT declaration. Bracketed groups are legal in those declarations' content models, but the stdlib's minimal declaration scanner does not implement them — only <!DOCTYPE [...]> internal subsets are handled — so it aborts.","triggerScenarios":"html.parser.HTMLParser (or any ParserBase subclass) feeding markup like <!ELEMENT foo (a | b)* [ hidden ]> or <!ATTLIST x [ ... ]>. The scanner hits '[' with decltype already set to element/attlist/linktype/link and raises.","commonSituations":"Parsing DTD-bearing documents (older SGML-flavored HTML, EPUB/DocBook fragments, scraped legacy pages with inline declarations); test fixtures containing raw DTD text; feeding a full .dtd file into HTMLParser by mistake.","solutions":["Strip or skip <!...> declaration blocks before feeding data to HTMLParser (they carry no document content for HTML purposes).","Catch AssertionError around feed() and skip/repair the offending declaration chunk, then resume feeding after the next '>'.","Use a real XML/SGML tool (xml.sax, lxml) for documents that genuinely need DTD internal subsets.","Override _scan_decl in a subclass to tolerate bracketed content models by scanning to the matching bracket first."],"exampleFix":"# before\nfrom html.parser import HTMLParser\nHTMLParser().feed('<!ELEMENT doc (title) [ #PCDATA ]>')  # AssertionError\n\n# after\nimport re\nfrom html.parser import HTMLParser\n\nclean = re.sub(r'<!\\[?[^>]*\\]?>', '', raw_markup)  # drop declarations\nHTMLParser().feed(clean)","handlingStrategy":"try-catch","validationCode":"import re\n\ndef decl_is_safe(chunk: str) -> bool:\n    \"\"\"Reject declarations containing '[' outside a doctype.\"\"\"\n    m = re.match(r'<!\\s*(\\w+)', chunk)\n    if not m:\n        return True\n    return m.group(1).lower() == 'doctype' or '[' not in chunk","typeGuard":null,"tryCatchPattern":"try:\n    parser.feed(data)\nexcept AssertionError as e:\n    if 'unsupported' in str(e) or 'char in declaration' in str(e):\n        end = data.find('>', parser.rawdata.find('<!'))\n        parser.reset(); parser.feed(data[end + 1:])\n    else:\n        raise","preventionTips":["Strip DTD-style declarations before feeding HTMLParser.","Use xml/lxml for documents with real content-model declarations.","Fuzz-test parser feeds with legacy SGML corpora to catch these early."],"tags":["markup","html-parser","dtd","parsing"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}