Skip to content

toc + attr_list: bare {id} attribute crashes toc with TypeError (unescape(None)) #1705

Open

Description

@rahul05ranjan

Problem description

Enabling the toc extension together with attr_list raises an unhandled TypeError for any heading that carries a bare (valueless) attribute — the simplest case being {id}:

import markdown
from markdown.extensions import attr_list, toc

markdown.markdown(
    "#d {id}",
    extensions=[attr_list.AttrListExtension(), toc.TocExtension()],
)
Traceback (most recent call last):
  File "markdown/extensions/toc.py", line 417, in run
    'id': unescape(el.attrib["id"]),
  ...
  File "markdown/treeprocessors.py", line 470, in unescape
    return self.RE.sub(self._unescape, text)
TypeError: expected string or bytes-like object, got 'NoneType'

Steps to reproduce

See above — current main (a4d4428), Python 3.13.

What happens

attr_list supports bare attributes ({attr} → valueless HTML attribute) and implements them with elem.set(name, None). For a heading, toc's treeprocessor then runs:

if "id" not in el.attrib:            # "id" IS in attrib — with value None
    el.attrib["id"] = unique(...)    # so the slug is never generated
...
'id': unescape(el.attrib["id"]),    # unescape(None) → TypeError

The id attribute exists but has the value None, so toc skips generating a slug for it and later passes the None to re.sub. With only attr_list (no toc) the same input renders <h1 id>d</h1>, i.e. the attribute really is valueless — which as an HTML id is no id at all.

Expected behavior

A valueless id should be treated like a missing id: the toc extension should generate a slug id (and an anchor) for the heading instead of crashing. #d {id} should render like any other heading with no explicit id.

Found by mutation-fuzzing the parser with the bundled extensions enabled. I used AI to assist me with this report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions