sqlalchemy/sqlalchemy · error · TypeError
Boolean value of this clause is not defined
Error message
Boolean value of this clause is not defined
What it means
`ClauseElement.__bool__` is intentionally defined to raise `TypeError` so that clause elements are never coerced to True/False. SQLAlchemy columns overload `==`/`!=` to build SQL expressions instead of returning booleans, so using a column or clause in a Python boolean context (`if`, `and`, `or`, `not`, ternary) is almost always a bug. The design prevents silent mistakes where `if col == val:` would otherwise always be truthy.
Source
Thrown at lib/sqlalchemy/sql/elements.py:787
return compiled_sql, extracted_params, param_dict, cache_hit
def __invert__(self):
# undocumented element currently used by the ORM for
# relationship.contains()
if hasattr(self, "negation_clause"):
return self.negation_clause
else:
return self._negate()
def _negate(self) -> ClauseElement:
# TODO: this code is uncovered and in all likelihood is not included
# in any codepath. So this should raise NotImplementedError in 2.1
grouped = self.self_group(against=operators.inv)
assert isinstance(grouped, ColumnElement)
return UnaryExpression(grouped, operator=operators.inv)
def __bool__(self):
raise TypeError("Boolean value of this clause is not defined")
def __repr__(self):
friendly = self.description
if friendly is None:
return object.__repr__(self)
else:
return "<%s.%s at 0x%x; %s>" % (
self.__module__,
self.__class__.__name__,
id(self),
friendly,
)
class DQLDMLClauseElement(ClauseElement):
"""represents a :class:`.ClauseElement` that compiles to a DQL or DML
expression, not DDL.
View on GitHub (pinned to d9b44cb731)
Solutions
- Build the comparison inside a query/`where()` clause rather than in Python control flow: `select(User).where(User.name == 'admin')`.
- If you must compare in Python, access the underlying loaded value via the instance attribute (e.g. `user.name`) after fetching the row, not the column expression object.
- For optional-value checks use `is None`/`is not None` on instance attributes, never on the class-level mapped column.
- Wrap with `bool()` only on a concrete scalar value, never on a `ColumnElement`/`ClauseElement`.
Example fix
# before
if User.name == "admin": # Boolean value of this clause is not defined
...
# after
admin = session.scalar(select(User).where(User.name == "admin"))
if admin is not None:
... Defensive patterns
Strategy: validation
Validate before calling
from sqlalchemy.sql.elements import ClauseElement
def assert_plain_python(value, where="here"):
"""Guard against accidentally truth-testing a SQL clause in an `if`/`and`/`or`."""
if isinstance(value, ClauseElement):
raise TypeError(
f"SQL clause {value!r} used in a boolean context {where}. "
"Put it inside .where() / and_() / or_() instead of `if`.")
return value
# usage (catches `if user.c.name == 'x': ...` style bugs at runtime):
# assert_plain_python(user.c.name == 'x')
#
# lints: also enable `sqlalchemy` plugin for mypy / use `# noqa` review. Type guard
from typing import Any, TypeGuard
from sqlalchemy.sql.elements import ClauseElement
def is_sql_clause(value: Any) -> TypeGuard[ClauseElement]:
"""True for any SQL expression that must NOT be evaluated as a Python bool."""
return isinstance(value, ClauseElement) Prevention
- Never write `if some_column_expr:` or `if col == val:` — columns are not Python booleans.
- Use `is None` / `is not None` to test for missing objects, never `if column:`.
- Combine criteria with sqlalchemy.and_()/or_() or the & / | operators, never Python `and`/`or`.
- Enable mypy with sqlalchemy plugin and ruff/flake8 to catch truthiness of ClauseElement statically.
When it happens
Trigger: `if column == 5: ...`; `column1 and column2`; `not column`; `bool(clause)`; `assert column == other`; ternary `x if column else y`; passing a column to `any()`/`all()` which evaluate truthiness; set/dict membership where hash collision triggers `__eq__` then `__bool__` on the resulting `BinaryExpression`.
Common situations: Writing `if user.name == 'admin':` on a mapped attribute/column inside Python logic instead of a query; mixing SQL building with control flow; copy-pasted Python conditionals over ORM fields; linting-disabled branches that test columns for truthiness.
Related errors
- This SQL expression has no entity namespace with which to fi
- Operator '%s' is not supported on this expression
- params() is not supported for INSERT/UPDATE/DELETE statement
- Object %r associated with '.type' attribute is not a TypeEng
- Neither %r object nor %r object has an attribute %r
AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01).
Data as JSON: /data/errors/5a24a20272eb00c6.json.
Report an issue: GitHub.