python/cpython · error · TypeError

%r can't have docstrings

Error message

%r can't have docstrings

What it means

get_docstring only accepts node types that can syntactically carry a docstring: Module, ClassDef, FunctionDef, AsyncFunctionDef. Passing any other AST node (Expression, Assign, If, etc.) raises TypeError with the node's class name. Note this is about the node kind, not about whether a docstring exists — an eligible node without a docstring returns None instead of raising.

Solutions

  1. Pass the module node or an actual def/class node: ast.get_docstring(tree) or ast.get_docstring(node) after isinstance filtering.
  2. Guard the call: if isinstance(node, (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)).
  3. When iterating statements, skip non-docstring-bearing nodes instead of blindly forwarding them.

Example fix

# before
first = tree.body[0]
text = ast.get_docstring(first)  # first is an Assign -> TypeError

# after
for node in tree.body:
    if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
        text = ast.get_docstring(node)
        break
Defensive patterns

Strategy: type-guard

Validate before calling

DOCSTRING_NODES = (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)

def docstring_of(node):
    if isinstance(node, DOCSTRING_NODES):
        return ast.get_docstring(node)
    return None

Type guard

def can_have_docstring(node) -> bool:
    return isinstance(node, (ast.Module, ast.ClassDef,
                             ast.FunctionDef, ast.AsyncFunctionDef))

Try / catch

try:
    text = ast.get_docstring(node)
except TypeError as e:
    if "can't have docstrings" in str(e):
        text = None  # node kind cannot carry a docstring; treat as absent

Prevention

When it happens

Trigger: ast.get_docstring(tree.body[0]) where the first statement is an Assign (module-level constant) rather than an Expr/FunctionDef; calling it on an Expression wrapper instead of the Module; feeding nodes from a custom visitor that yields non-def nodes.

Common situations: Docstring extractors iterating module bodies assuming the first statement is always a def/class; processing notebooks or generated code where a pragma or __future__ import precedes functions; tools that walk all nodes and call get_docstring unconditionally.

Related errors


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

Appendix: source

Thrown at Lib/ast.py:340

        if isinstance(field, AST):
            yield field
        elif isinstance(field, list):
            for item in field:
                if isinstance(item, AST):
                    yield item


def get_docstring(node, clean=True):
    """
    Return the docstring for the given node or None if no docstring can
    be found.  If the node provided does not have docstrings a TypeError
    will be raised.

    If *clean* is `True`, all tabs are expanded to spaces and any whitespace
    that can be uniformly removed from the second line onwards is removed.
    """
    if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)):
        raise TypeError("%r can't have docstrings" % node.__class__.__name__)
    if not(node.body and isinstance(node.body[0], Expr)):
        return None
    node = node.body[0].value
    if isinstance(node, Constant) and isinstance(node.value, str):
        text = node.value
    else:
        return None
    if clean:
        import inspect
        text = inspect.cleandoc(text)
    return text


_line_pattern = None
def _splitlines_no_ff(source, maxlines=None):
    """Split a string into lines ignoring form feed and other chars.

    This mimics how the Python parser splits source code.

View on GitHub (pinned to bc6749cc3b)