boto/boto3 · error · TypeError

Value must be a nonempty dictionary whose key is a valid…

Error message

Value must be a nonempty dictionary whose key is a valid dynamodb type.

What it means

TypeDeserializer.deserialize expects a nonempty dict shaped like {'S': ...}, {'N': ...}, etc. The first check 'if not value' catches None, {}, and other falsy inputs and raises TypeError, because an empty dictionary gives no type key to dispatch on.

Solutions

  1. Skip or default None/empty dict inputs before calling deserialize.
  2. Validate that the value is a dict with exactly one key that is a known DynamoDB type tag.
  3. Build a small helper that returns None for empty/None payloads instead of forwarding them.

Example fix

# before
d = TypeDeserializer()
val = d.deserialize({})
# after
d = TypeDeserializer()
raw = {}
val = d.deserialize(raw) if raw else None
Defensive patterns

Strategy: validation

Validate before calling

VALID = {'S','N','B','SS','NS','BS','BOOL','NULL','L','M'}
def safe_deserialize(d, TypeDeserializer):
    if not isinstance(d, dict) or not d:
        return None
    assert set(d).issubset(VALID), f'unexpected type tags: {set(d) - VALID}'
    return TypeDeserializer().deserialize(d)

Type guard

VALID = {'S','N','B','SS','NS','BS','BOOL','NULL','L','M'}
def is_dynamo_value(v) -> bool:
    return isinstance(v, dict) and len(v) == 1 and next(iter(v)) in VALID

Try / catch

from boto3.dynamodb.types import TypeDeserializer
d = TypeDeserializer()
try:
    val = d.deserialize(raw)
except TypeError:
    val = None

Prevention

When it happens

Trigger: Calling TypeDeserializer().deserialize({}) or deserialize(None); receiving a malformed attribute value from a non-AWS source or a hand-built dict where the value was popped.

Common situations: Iterating over item attributes and accidentally passing an empty dict; integrating DynamoDB Streams data that has been filtered; testing with placeholder empty values.

Related errors


AI-assisted analysis of boto/boto3@6e10b029c1 (2026-08-11). Data as JSON: /api/errors/3614ab5464d8d4ae. Report an issue: GitHub.

Appendix: source

Thrown at boto3/dynamodb/types.py:269

            DynamoDB                                Python
            --------                                ------
            {'NULL': True}                          None
            {'BOOL': True/False}                    True/False
            {'N': str(value)}                       Decimal(str(value))
            {'S': string}                           string
            {'B': bytes}                            Binary(bytes)
            {'NS': [str(value)]}                    set([Decimal(str(value))])
            {'SS': [string]}                        set([string])
            {'BS': [bytes]}                         set([bytes])
            {'L': list}                             list
            {'M': dict}                             dict

        :returns: The pythonic value of the DynamoDB type.
        """

        if not value:
            raise TypeError(
                'Value must be a nonempty dictionary whose key '
                'is a valid dynamodb type.'
            )
        dynamodb_type = list(value.keys())[0]
        try:
            deserializer = getattr(
                self, f'_deserialize_{dynamodb_type}'.lower()
            )
        except AttributeError:
            raise TypeError(f'Dynamodb type {dynamodb_type} is not supported')
        return deserializer(value[dynamodb_type])

    def _deserialize_null(self, value):
        return None

    def _deserialize_bool(self, value):
        return value

View on GitHub (pinned to 6e10b029c1)