python/cpython · error · AssertionError

unexpected '[' char in declaration

Error message

unexpected '[' char in declaration

What it means

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.

Source

Thrown at Lib/_markupbase.py:132

                if not m:
                    return -1 # incomplete
                j = m.end()
            elif c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
                name, j = self._scan_name(j, i)
            elif c in self._decl_otherchars:
                j = j + 1
            elif c == "[":
                # this could be handled in a separate doctype parser
                if decltype == "doctype":
                    j = self._parse_doctype_subset(j + 1, i)
                elif decltype in {"attlist", "linktype", "link", "element"}:
                    # must tolerate []'d groups in a content model in an element declaration
                    # also in data attribute specifications of attlist declaration
                    # also link type declaration subsets in linktype declarations
                    # also link attribute specification lists in link declarations
                    raise AssertionError("unsupported '[' char in %s declaration" % decltype)
                else:
                    raise AssertionError("unexpected '[' char in declaration")
            else:
                raise AssertionError("unexpected %r char in declaration" % rawdata[j])
            if j < 0:
                return j
        return -1 # incomplete

    # Internal -- parse a marked section
    # Override this to handle MS-word extension syntax <![if word]>content<![endif]>
    def parse_marked_section(self, i, report=1):
        rawdata= self.rawdata
        assert rawdata[i:i+3] == '<![', "unexpected call to parse_marked_section()"
        sectName, j = self._scan_name( i+3, i )
        if j < 0:
            return j
        if sectName in {"temp", "cdata", "ignore", "include", "rcdata"}:
            # look for standard ]]> ending
            match= _markedsectionclose.search(rawdata, i+3)
        elif sectName in {"if", "else", "endif"}:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Sanitize input: remove unknown '<!...>' blocks before feeding the parser.
  2. Wrap feed() in try/except AssertionError and resume after the closing '>' of the bad construct (find it with rawdata.find('>')).
  3. For conditional comments <![if ...]>, subclass HTMLParser and override parse_marked_section / unknown_decl instead of letting the base scanner see them.
  4. Validate markup with a tolerant library (bleach, html5lib) if input provenance is untrusted.

Example fix

# before
HTMLParser().feed('<!custom [ data ]>')  # AssertionError: unexpected '[' char in declaration

# after
import re
feed = re.sub(r'<![!\w-]*\s*\[.*?\]?>?', '', raw)  # strip bracketed decls
HTMLParser().feed(feed)
Defensive patterns

Strategy: try-catch

Validate before calling

import re
_DECL_OK = re.compile(r'<!\s*(doctype|element|attlist|entity|notation)\b[^\[]*>', re.I)

def declarations_ok(raw: str) -> bool:
    return all(_DECL_OK.match(d) or '[' not in d for d in re.findall(r'<![^>]*>', raw))

Try / catch

try:
    parser.feed(data)
except AssertionError as e:
    if 'declaration' in str(e):
        bad = data.rfind('<!', 0, parser.offset + 1)
        data = data[:bad] + data[data.find('>', bad) + 1:]
        parser.reset(); parser.feed(data)
    else:
        raise

Prevention

When it happens

Trigger: 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 '['.

Common situations: 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.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/a8b40a9aab9ad1b3. Report an issue: GitHub.