{"record":{"id":"06fae2e99da4e606","repo":"python/cpython","slug":"unexpected-r-char-in-declaration","errorCode":null,"errorMessage":"unexpected %r char in declaration","messagePattern":"unexpected %r char in declaration","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Lib/_markupbase.py","lineNumber":134,"sourceCode":"                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\"}:\n            # look for MS Office ]> ending\n            match= _msmarkedsectionclose.search(rawdata, i+3)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_markupbase.py#L116-L152","documentation":"AssertionError raised by _markupbase.ParserBase._scan_decl when a declaration contains a character the scanner has no rule for — not a name char, not one of _decl_otherchars, not '['. It is the catch-all for malformed <!NAME ...> bodies, echoing the offending character.","triggerScenarios":"HTMLParser.feed() with a declaration containing stray punctuation/control characters, e.g. <!DOCTYPE html!> or <!ATTLIST a b 'weird>; unterminated or truncated declarations at buffer end can also leave the cursor on an unexpected character.","commonSituations":"Parsing minified/mangled HTML, template fragments with leftover '<!' tokens, binary data fed as text, or feeding a document in chunks where a declaration is split and the tail begins mid-syntax.","solutions":["Feed the parser complete declarations (or use feed(data) followed by close() so buffering completes) instead of pre-splitting markup.","Pre-filter input: remove or neutralize stray '<!' sequences that are not valid comments/doctype.","Catch AssertionError, log the position via parser.getpos(), and skip past the next '>' before continuing.","For untrusted HTML, run a repair pass (html5lib, bleach.cleaner) before stdlib parsing."],"exampleFix":"# before\nHTMLParser().feed(\"<!DOCTYPE html^>\")  # AssertionError: unexpected '^' char in declaration\n\n# after\nraw = re.sub(r'<!([\\w-]+)[^>]*>', lambda m: m.group(0) if m.group(1).lower()=='doctype' else '', raw)\nHTMLParser().feed(raw)","handlingStrategy":"try-catch","validationCode":"import re\n_BAD_DECL_CHAR = re.compile(r'<!\\s*[\\w-]+[^>]*[^\\w\\s\\[\\]\\|()\\'\\\",#%-]>')\n\ndef decl_chars_ok(raw: str) -> bool:\n    return not _BAD_DECL_CHAR.search(raw)","typeGuard":null,"tryCatchPattern":"try:\n    parser.feed(chunk)\nexcept AssertionError as e:\n    if 'char in declaration' in str(e):\n        chunk = re.sub(r'<![^>]*>', '', chunk)  # drop the offending declaration\n        parser.reset(); parser.feed(chunk)\n    else:\n        raise","preventionTips":["Always call parser.close() after the last feed() so truncated declarations resolve or fail cleanly.","Pre-filter stray '<!' sequences from template output.","Log parser.getpos() on failure to pinpoint the malformed declaration."],"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"}