boto3: Parameter validation failed (ParamValidationError)
TL;DR — botocore.exceptions.ParamValidationError is raised on your machine, before any request is sent — the arguments you passed don't match the operation's expected shape. In DynamoDB code it's almost always a client-vs-resource mixup: the low-level client wants DynamoDB-JSON ({'S': 'abc'}, numbers as strings), the Table resource wants native Python types. Match the style to the interface you're calling.
What it means
botocore.exceptions.ParamValidationError: Parameter validation failed:
Invalid type for parameter Item.price.N, value: 42, type: <class 'int'>,
valid types: <class 'str'>botocore validates every call against the service's API model before signing it. A failure here is not a ClientError — DynamoDB never saw the request — so except ClientError won't catch it, and no network round trip happened. The message names the exact parameter path that failed and the type it expected.
Why it happens
- Native Python values passed to the low-level client —
boto3.client('dynamodb')speaks raw DynamoDB JSON: every attribute is a type-tagged map andNvalues are strings ({'N': '42'}, not42). - DynamoDB-JSON passed to the
Tableresource — the reverse mixup:boto3.resource('dynamodb').Table(...)expects plain Python values and does the marshalling for you. - Condition objects where a string is expected — the query paginator's
KeyConditionExpressionaccepts a string expression;Key('pk').eq(...)objects fail validation there. - A typo'd or unsupported parameter name — unknown keys fail validation; an outdated botocore can also reject parameters added to the API after its bundled model.
How to fix it
Pick one interface and use its type style consistently:
# Table resource — native Python types table = boto3.resource('dynamodb').Table('orders') table.put_item(Item={'pk': 'ORDER#1', 'price': Decimal('42')}) # Low-level client — DynamoDB-JSON, numbers as strings client = boto3.client('dynamodb') client.put_item(TableName='orders', Item={'pk': {'S': 'ORDER#1'}, 'price': {'N': '42'}})Use string expressions with paginators —
KeyConditionExpression='pk = :p'plusExpressionAttributeValues, or paginate theTableresource manually withLastEvaluatedKey.Read the parameter path in the message —
Item.price.Ntells you exactly which attribute and which type tag failed; fix that one field rather than guessing.Upgrade botocore for "Unknown parameter" failures — if the parameter is real but your validation model predates it,
pip install -U boto3 botocore.Catch it separately from service errors:
from botocore.exceptions import ClientError, ParamValidationError try: client.put_item(**kwargs) except ParamValidationError as e: # local: fix the call ... except ClientError as e: # remote: DynamoDB rejected it ...
Hand-writing DynamoDB-JSON is where these type tags go wrong — the DynamoDB JSON converter translates between native JSON and the type-tagged wire format, and the DynoTable desktop app edits items with the marshalling handled for you.
Related errors
- Float types are not supported — boto3's other client-side type rejection (use
Decimal). - ValidationException: One or more parameter values were invalid — the server-side counterpart once the request does go out.
- Learn: DynamoDB JSON & marshalling
References
- Error handling — Boto3 documentation
- AttributeValue — Amazon DynamoDB API Reference
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.