python/cpython · error · ValueError
Node can't use cause without an exception.
Error message
Node can't use cause without an exception.
What it means
Raised by ast.unparse() (via Lib/_ast_unparse.py visit_Raise) when a Raise AST node has exc=None but a non-None cause. In valid Python source this cannot happen because 'raise from cause' always requires an expression, so the node was almost certainly built programmatically or mangled by a transformation pass. The unparser refuses to emit a bare 'from' clause with nothing to raise.
Source
Thrown at Lib/_ast_unparse.py:341
self.write("yield")
if node.value:
self.write(" ")
self.set_precedence(_Precedence.ATOM, node.value)
self.traverse(node.value)
def visit_YieldFrom(self, node):
with self.require_parens(_Precedence.YIELD, node):
self.write("yield from ")
if not node.value:
raise ValueError("Node can't be used without a value attribute.")
self.set_precedence(_Precedence.ATOM, node.value)
self.traverse(node.value)
def visit_Raise(self, node):
self.fill("raise")
if not node.exc:
if node.cause:
raise ValueError(f"Node can't use cause without an exception.")
return
self.write(" ")
self.traverse(node.exc)
if node.cause:
self.write(" from ")
self.traverse(node.cause)
def do_visit_try(self, node):
self.fill("try", allow_semicolon=False)
with self.block():
self.traverse(node.body)
for ex in node.handlers:
self.traverse(ex)
if node.orelse:
self.fill("else", allow_semicolon=False)
with self.block():
self.traverse(node.orelse)
if node.finalbody:View on GitHub (pinned to bc6749cc3b)
Solutions
- Set node.exc to an ast expression (e.g. ast.Name(id='ValueError', ctx=ast.Load())) before unparsing, or construct a real raise statement.
- If you intended a bare 'raise', set node.cause = None so the node reverts to a legal form.
- Add an assertion/guard in your transformer that a Raise node never keeps a cause when its exc is removed.
- Build the node with ast.Raise(exc=..., cause=...) in one step instead of mutating fields afterwards.
Example fix
// before
node = ast.Raise(exc=None, cause=ast.Name(id='KeyError', ctx=ast.Load()))
ast.unparse(node) # ValueError: Node can't use cause without an exception.
// after
node = ast.Raise(
exc=ast.Call(func=ast.Name(id='ValueError', ctx=ast.Load()), args=[], keywords=[]),
cause=ast.Name(id='KeyError', ctx=ast.Load()),
)
ast.unparse(node) # 'ValueError() from KeyError' Defensive patterns
Strategy: validation
Validate before calling
import ast
def valid_raise(node: ast.Raise) -> bool:
return not (node.exc is None and node.cause is not None)
# before unparsing any transformed tree:
for n in ast.walk(tree):
if isinstance(n, ast.Raise) and not valid_raise(n):
n.cause = None # or set n.exc Type guard
def is_valid_raise(node: ast.AST) -> bool is not applicable; use:
def raise_ok(n: ast.AST) -> bool:
return not (isinstance(n, ast.Raise) and n.exc is None and n.cause is not None) Try / catch
try:
src = ast.unparse(tree)
except ValueError as e:
if 'cause without an exception' in str(e):
for n in ast.walk(tree):
if isinstance(n, ast.Raise) and n.exc is None:
n.cause = None
src = ast.unparse(tree)
else:
raise Prevention
- In AST transform passes, treat exc and cause as a pair: clear cause whenever exc is removed.
- Unit-test unparsing of every tree your transformer emits.
- Prefer building Raise nodes in one constructor call instead of mutating fields.
When it happens
Trigger: Calling ast.unparse(node) on an ast.Raise where node.exc is None and node.cause is not None. Typical producers: AST rewrite/optimization passes that replace the exception expression with None, hand-built trees that set cause while leaving exc unset, or copying a cause onto a re-raise node.
Common situations: Writing a lint/transform tool that edits Raise nodes; porting code that constructs AST nodes literally; partial construction of a Raise node where exc is filled in later but unparse is called too early.
Related errors
- Unexpected node inside JoinedStr, {node!r}
- Callable must be used as Callable[[arg, ...], result].
- Expected a list of types, an ellipsis, ParamSpec, or Concate
- module 'collections.abc' has no attribute {attr!r}
- Expected Theme object, found {t}
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/242418f5e6170959.
Report an issue: GitHub.