{"record":{"id":"e3a5d704c0a68286","repo":"python/cpython","slug":"expected-ast-got-r","errorCode":null,"errorMessage":"expected AST, got %r","messagePattern":"expected AST, got %r","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/ast.py","lineNumber":223,"sourceCode":"                    args.append(f'{t.attribute}{name}{t.reset}={value}')\n            cls_name = f'{t.node}{cls.__name__}{t.reset}'\n            if allsimple and len(args) <= 3:\n                return f'{cls_name}({\", \".join(args)})', not args\n            return f'{cls_name}({prefix}{sep.join(args)})', False\n        elif isinstance(node, list):\n            if not node:\n                return '[]', True\n            return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x in node)), False\n        if isinstance(node, bool) or node is None or node is Ellipsis:\n            return f'{t.keyword}{node!r}{t.reset}', True\n        if isinstance(node, (int, float, complex)):\n            return f'{t.number}{node!r}{t.reset}', True\n        if isinstance(node, (str, bytes)):\n            return f'{t.string}{node!r}{t.reset}', True\n        return repr(node), True\n\n    if not isinstance(node, AST):\n        raise TypeError('expected AST, got %r' % node.__class__.__name__)\n    if indent is not None and not isinstance(indent, str):\n        indent = ' ' * indent\n    return _format(node)[0]\n\n\ndef copy_location(new_node, old_node):\n    \"\"\"\n    Copy source location (`lineno`, `col_offset`, `end_lineno`, and `end_col_offset`\n    attributes) from *old_node* to *new_node* if possible, and return *new_node*.\n    \"\"\"\n    for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':\n        if attr in old_node._attributes and attr in new_node._attributes:\n            value = getattr(old_node, attr, None)\n            # end_lineno and end_col_offset are optional attributes, and they\n            # should be copied whether the value is None or not.\n            if value is not None or (\n                hasattr(old_node, attr) and attr.startswith(\"end_\")\n            ):","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/ast.py#L205-L241","documentation":"ast.dump requires a single AST node instance as its first argument; after its internal _format helper handles lists/None/bools/numbers/strings, the top-level check rejects anything that is not an ast.AST instance with TypeError naming the offending class. Lists of nodes, source strings, tokens, or None passed at top level all fail here.","triggerScenarios":"ast.dump(parse_result.body) where body is a list of statements (must pick one node, e.g. body[0]); ast.dump('x = 1') forgetting ast.parse first; passing the result of ast.walk(...) (a generator); mixing up argument order in helper functions that wrap dump.","commonSituations":"Debugging helpers that dump 'whatever the traversal returned'; refactors that changed a single-node variable into a list; logging visitor output where lists of nodes are the natural unit.","solutions":["Call ast.parse(source) first and pass its result (a Module node) or an individual statement/expression node.","For lists of nodes, dump each element: '\\n'.join(ast.dump(n) for n in tree.body).","Type-check before dumping when the node's provenance is dynamic: isinstance(node, ast.AST)."],"exampleFix":"# before\nast.dump(tree.body)  # list of stmts -> TypeError: expected AST, got 'list'\n\n# after\nast.dump(tree)                    # whole module\n# or\n'\\n'.join(ast.dump(n) for n in tree.body)","handlingStrategy":"type-guard","validationCode":"if not isinstance(obj, ast.AST):\n    obj = ast.parse(obj)  # accept source strings defensively before dump","typeGuard":"import ast\n\ndef is_ast_node(obj) -> bool:\n    return isinstance(obj, ast.AST)\n\ndef dump_any(obj):\n    if isinstance(obj, ast.AST):\n        return ast.dump(obj)\n    if isinstance(obj, (list, tuple)):\n        return '\\n'.join(ast.dump(n) for n in obj if isinstance(n, ast.AST))\n    raise TypeError(f'cannot dump {type(obj).__name__}')","tryCatchPattern":"try:\n    text = ast.dump(node)\nexcept TypeError as e:\n    if 'expected AST' in str(e):\n        text = '\\n'.join(ast.dump(n) for n in node)  # was a list of nodes","preventionTips":["Always run ast.parse before dump when starting from source text.","Remember tree.body is a list — index it before dumping individual statements.","Keep helper functions typed so a list of nodes never reaches ast.dump."],"tags":["ast","dump","typeerror","debugging"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}