{"id":"be1e55cea141d9fe","repo":"boto/boto3","slug":"attribute-object-value-name-is-of-type-type-val","errorCode":null,"errorMessage":"Attribute object {value.name} is of type {type(value)}. KeyConditionExpression only supports Attribute objects of type Key","messagePattern":"Attribute object (.+?) is of type (.+?)\\. KeyConditionExpression only supports Attribute objects of type Key","errorType":"exception","errorClass":"DynamoDBNeedsKeyConditionError","httpStatus":null,"severity":"error","filePath":"boto3/dynamodb/conditions.py","lineNumber":407,"sourceCode":"        attribute_value_placeholders,\n        has_grouped_values,\n        is_key_condition,\n    ):\n        # Continue to recurse if the value is a ConditionBase in order\n        # to extract out all parts of the expression.\n        if isinstance(value, ConditionBase):\n            return self._build_expression(\n                value,\n                attribute_name_placeholders,\n                attribute_value_placeholders,\n                is_key_condition,\n            )\n        # If it is not a ConditionBase, we can recurse no further.\n        # So we check if it is an attribute and add placeholders for\n        # its name\n        elif isinstance(value, AttributeBase):\n            if is_key_condition and not isinstance(value, Key):\n                raise DynamoDBNeedsKeyConditionError(\n                    f'Attribute object {value.name} is of type {type(value)}. '\n                    f'KeyConditionExpression only supports Attribute objects '\n                    f'of type Key'\n                )\n            return self._build_name_placeholder(\n                value, attribute_name_placeholders\n            )\n        # If it is anything else, we treat it as a value and thus placeholders\n        # are needed for the value.\n        else:\n            return self._build_value_placeholder(\n                value, attribute_value_placeholders, has_grouped_values\n            )\n\n    def _build_name_placeholder(self, value, attribute_name_placeholders):\n        attribute_name = value.name\n        # Figure out which parts of the attribute name that needs replacement.\n        attribute_name_parts = ATTR_NAME_REGEX.findall(attribute_name)","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/boto/boto3/blob/c7b4afac237b976d48395d7523eaf7cec3a450b3/boto3/dynamodb/conditions.py#L389-L425","documentation":"Raised in _build_expression_component when is_key_condition is True and an AttributeBase operand is an Attr (not a Key). DynamoDB's KeyConditionExpression may only reference partition/sort key attributes represented by Key(...); using Attr(...) (which denotes a non-key item attribute) is semantically invalid for key conditions. The builder explicitly checks isinstance(value, Key) and rejects Attr objects.","triggerScenarios":"table.query(KeyConditionExpression=Attr('pk').eq('v')) — used Attr instead of Key. Also Key('pk').eq('v') & Attr('sk').begins_with('s') where the sort-key side is an Attr.","commonSituations":"Copy-pasting a FilterExpression (built with Attr) into KeyConditionExpression; not knowing that Key vs Attr is enforced positionally; renaming attributes during a schema migration.","solutions":["Use Key(...) for every attribute in a KeyConditionExpression: Key('pk').eq('v').","For sort-key range conditions also use Key: Key('pk').eq('v') & Key('sk').begins_with('s').","Reserve Attr(...) exclusively for FilterExpression / ConditionExpression (non-key filters)."],"exampleFix":"# before\ntable.query(KeyConditionExpression=Attr('pk').eq('user#1'))\n\n# after\ntable.query(KeyConditionExpression=Key('pk').eq('user#1'))","handlingStrategy":"type-guard","validationCode":"from boto3.dynamodb.conditions import Key, AttributeBase\n\ndef validate_key_condition(expr):\n    # crude check: ensure no Attr leaks in by scanning repr\n    if 'Attr' in repr(expr):\n        raise TypeError('KeyConditionExpression must use Key(), not Attr()')\n    return expr","typeGuard":"from boto3.dynamodb.conditions import Key\n\ndef is_key(obj) -> bool:\n    return isinstance(obj, Key)","tryCatchPattern":"from boto3.exceptions import DynamoDBNeedsKeyConditionError\ntry:\n    table.query(KeyConditionExpression=kce)\nexcept DynamoDBNeedsKeyConditionError:\n    # rebuild using Key() instead of Attr()\n    table.query(KeyConditionExpression=Key('pk').eq('v'))","preventionTips":["Convention: Key() for key-conditions, Attr() for filter/condition expressions only.","Review any KeyConditionExpression that was adapted from a FilterExpression.","Add a lint rule that flags Attr( inside a query() call."],"tags":["dynamodb","conditions","key-condition","key-vs-attr"],"analyzedSha":"c7b4afac237b976d48395d7523eaf7cec3a450b3","analyzedAt":"2026-08-04T20:35:51.598Z","schemaVersion":2}