pandas-dev/pandas · error · TypeError
Expression objects are not copiable
Error message
Expression objects are not copiable
What it means
Raised by Expression.__copy__ (typed NoReturn) when copy.copy() is called on a pandas.api.typing.Expression. Expression objects intentionally forbid shallow copies to preserve their identity as deferred singletons bound to a specific closure; copying them could break the func->DataFrame evaluation chain. The same message is reused for both __copy__ and __deepcopy__.
Solutions
- Do not copy Expression objects; treat them as opaque singletons.
- Filter Expression out before copying: skip objects whose type name is 'Expression'.
- Re-create the Expression from its source via pd.col(name) if you need a logically equivalent one.
Example fix
// before
expr2 = copy.copy(pd.col('a'))
// after
expr2 = pd.col('a') # same singleton, or rebuild from name Defensive patterns
Strategy: type-guard
Validate before calling
from pandas.api.typing import Expression
if isinstance(obj, Expression):
raise TypeError('do not copy.copy() an Expression') Type guard
def is_expression(x) -> bool:
from pandas.api.typing import Expression
return isinstance(x, Expression) Prevention
- Treat Expression as an opaque singleton; never copy it.
- Filter Expression out before bulk copy.copy on collections.
When it happens
Trigger: copy.copy(pd.col('a')); a library that auto-copies its inputs (e.g. functools.partial dispatch, some ORM wrappers); pickle/copy protocols that fall back to __copy__.
Common situations: Calling copy.copy on a heterogeneous collection that happens to contain an Expression; framework code that defensively copies user-supplied callables.
Related errors
- boolean value of an expression is ambiguous
- Expression objects are not iterable
- Column ' ' not found in given DataFrame. Hint: did you mean…
- Expected Hashable, got
- Accumulation not supported for
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/67cb73c86e94a03d.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/col.py:363
evaluated.append((condition, replacement))
return ser.case_when(evaluated)
# Keep repr compact; caselist may be large.
repr_str = f"{self!r}.case_when(...)"
return Expression(func, repr_str)
def __repr__(self) -> str:
return self._repr_str or "Expr(...)"
# Unsupported ops
def __bool__(self) -> NoReturn:
raise TypeError("boolean value of an expression is ambiguous")
def __iter__(self) -> NoReturn:
raise TypeError("Expression objects are not iterable")
def __copy__(self) -> NoReturn:
raise TypeError("Expression objects are not copiable")
def __deepcopy__(self, memo: dict[int, Any] | None) -> NoReturn:
raise TypeError("Expression objects are not copiable")
@set_module("pandas")
def col(col_name: Hashable) -> Expression:
"""
Generate deferred object representing a column of a DataFrame.
Any place which accepts ``lambda df: df[col_name]``, such as
:meth:`DataFrame.assign` or :meth:`DataFrame.loc`, can also accept
``pd.col(col_name)``.
.. versionadded:: 3.0.0
Parameters
----------View on GitHub (pinned to 3b7651241d)