boto/boto3 · error · DynamoDBNeedsConditionError
Expecting a ConditionBase object. Got
Error message
Expecting a ConditionBase object. Got {value} of type {type(value)}. Use AttributeBase object methods (i.e. Attr().eq()). to generate ConditionBase instances. What it means
When building a ConditionExpression or KeyConditionExpression, boto3 requires the top-level condition argument to be a ConditionBase. If you pass a raw attribute, scalar, list, or string to ConditionExpressionBuilder.build_condition, it raises DynamoDBNeedsConditionError(condition) because there is no defined serialization for non-condition input.
Solutions
- Always pass a ConditionBase (result of Attr()/Key() comparison methods) to filter_expression / key_condition_expression.
- If you want a string-based expression, do not use boto3 conditions; use the botocore-level ExpressionAttributeNames/Values with a raw string instead.
- Validate dynamic conditions with isinstance(cond, ConditionBase) before passing them to the API.
Example fix
# before
table.query(KeyConditionExpression=Key('pk'), ...) # bare Key, no comparison
# after
table.query(KeyConditionExpression=Key('pk').eq('user#42'), ...) Defensive patterns
Strategy: type-guard
Validate before calling
from boto3.dynamodb.conditions import ConditionBase
def assert_condition(c, label):
assert isinstance(c, ConditionBase), \
f'{label} must be a ConditionBase; got {type(c).__name__}'
return c Type guard
from boto3.dynamodb.conditions import ConditionBase
def is_condition_expression(v) -> bool:
return isinstance(v, ConditionBase) Try / catch
from boto3.exceptions import DynamoDBNeedsConditionError
try:
table.scan(FilterExpression=expr)
except DynamoDBNeedsConditionError:
expr = Attr('x').eq(1) # rebuild properly Prevention
- Always build filter/key conditions from Attr()/Key() comparison methods.
- Never pass raw strings or values as the condition expression.
- Type-check conditions in dynamic builders before the API call.
When it happens
Trigger: Passing Attr('x') directly as filter_expression, passing a value like 'x = :v' as a hand-written string, or passing a dict/None where a ConditionBase is expected. Common when constructing Table.query(...) or Table.scan(...) conditions programmatically.
Common situations: Mixing boto3.dynamodb.conditions with raw string expressions; passing a Python value instead of Attr().eq(value); forgetting to call .eq()/.begins_with() on an attribute.
Related errors
- AND operation cannot be applied to value
- OR operation cannot be applied to value
- Attribute object is of type . KeyConditionExpression only…
- NOT operation cannot be applied to value
- Dynamodb type is not supported
AI-assisted analysis of boto/boto3@6e10b029c1 (2026-08-11).
Data as JSON: /api/errors/99c4ca6cb38bbd48.
Report an issue: GitHub.
Appendix: source
Thrown at boto3/dynamodb/conditions.py:344
:type condition: ConditionBase
:param condition: A condition to be built into a condition expression
string with any necessary placeholders.
:type is_key_condition: Boolean
:param is_key_condition: True if the expression is for a
KeyConditionExpression. False otherwise.
:rtype: (string, dict, dict)
:returns: Will return a string representing the condition with
placeholders inserted where necessary, a dictionary of
placeholders for attribute names, and a dictionary of
placeholders for attribute values. Here is a sample return value:
('#n0 = :v0', {'#n0': 'myattribute'}, {':v1': 'myvalue'})
"""
if not isinstance(condition, ConditionBase):
raise DynamoDBNeedsConditionError(condition)
attribute_name_placeholders = {}
attribute_value_placeholders = {}
condition_expression = self._build_expression(
condition,
attribute_name_placeholders,
attribute_value_placeholders,
is_key_condition=is_key_condition,
)
return BuiltConditionExpression(
condition_expression=condition_expression,
attribute_name_placeholders=attribute_name_placeholders,
attribute_value_placeholders=attribute_value_placeholders,
)
def _build_expression(
self,
condition,
attribute_name_placeholders,View on GitHub (pinned to 6e10b029c1)