python/cpython · error · AssertionError
unsupported '[' char in %s declaration
Error message
unsupported '[' char in %s declaration
What it means
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.
Source
Thrown at Lib/_markupbase.py:130
if c in "\"'":
m = _declstringlit_match(rawdata, j)
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 ]]> endingView on GitHub (pinned to bc6749cc3b)
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.
Example fix
# before
from html.parser import HTMLParser
HTMLParser().feed('<!ELEMENT doc (title) [ #PCDATA ]>') # AssertionError
# after
import re
from html.parser import HTMLParser
clean = re.sub(r'<!\[?[^>]*\]?>', '', raw_markup) # drop declarations
HTMLParser().feed(clean) Defensive patterns
Strategy: try-catch
Validate before calling
import re
def decl_is_safe(chunk: str) -> bool:
"""Reject declarations containing '[' outside a doctype."""
m = re.match(r'<!\s*(\w+)', chunk)
if not m:
return True
return m.group(1).lower() == 'doctype' or '[' not in chunk Try / catch
try:
parser.feed(data)
except AssertionError as e:
if 'unsupported' in str(e) or 'char in declaration' in str(e):
end = data.find('>', parser.rawdata.find('<!'))
parser.reset(); parser.feed(data[end + 1:])
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unexpected char in internal subset (in %r)
- unknown declaration %r in internal subset
- unexpected '[' char in declaration
- unexpected %r char in declaration
- unknown status keyword %r in marked section
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/b49eb35f4be4832c.
Report an issue: GitHub.