boto3: Parameter validation failed (ParamValidationError)

TL;DR — botocore.exceptions.ParamValidationError 是在你自己机器上抛出的,任何请求发出之前——你传的参数与该操作期望的形状对不上。在 DynamoDB 代码里,它几乎总是 client 与 resource 的混用:底层 client 要的是 DynamoDB JSON({'S': 'abc'},数字写成字符串),而 Table resource 要的是原生 Python 类型。把写法跟你调用的那个接口对齐。

含义

botocore.exceptions.ParamValidationError: Parameter validation failed:
Invalid type for parameter Item.price.N, value: 42, type: <class 'int'>,
valid types: <class 'str'>

# what the engine actually returns, reproduced against boto3 1.43.67 on Python 3.11.15:
ParamValidationError: Parameter validation failed:
Invalid type for parameter Item.price.N, value: 42, type: <class 'int'>, valid types: <class 'str'>

botocore 在签名之前会拿服务的 API 模型校验每一次调用。这里的失败不是 ClientError——DynamoDB 从没见过这个请求——所以 except ClientError 捕获不到它,也没有发生任何网络往返。消息会点名失败的那个确切参数路径,以及它期望的类型。

为什么会发生

  • 把原生 Python 值传给了底层 client——boto3.client('dynamodb') 说的是裸 DynamoDB JSON:每个属性都是一个带类型标签的映射,而 N 值是_字符串_({'N': '42'},不是 42)。
  • 把 DynamoDB JSON 传给了 Table resource——反过来的混用:boto3.resource('dynamodb').Table(...) 期望的是普通 Python 值,并会替你完成 marshalling。
  • 在需要字符串的地方给了条件对象——query paginator 的 KeyConditionExpression 接受的是字符串表达式;Key('pk').eq(...) 这类对象在那里过不了校验。
  • 参数名拼错或不受支持——未知的键过不了校验;过旧的 botocore 也可能拒绝那些在它内置模型之后才加进 API 的参数。

如何修复

  1. 选定一个接口,并一致地使用它的类型写法:

    # 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'}})
  2. 对 paginator 使用字符串表达式——KeyConditionExpression='pk = :p' 加上 ExpressionAttributeValues,或者用 LastEvaluatedKey 手工对 Table resource 分页。

  3. 读消息里的参数路径——Item.price.N 明确告诉你是哪个属性、哪个类型标签没过;去修那一个字段,而不是靠猜。

  4. 遇到 "Unknown parameter" 失败就升级 botocore——如果那个参数确实存在、只是你的校验模型比它更早,就 pip install -U boto3 botocore

  5. 把它与服务端错误分开捕获:

    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
        ...

手写 DynamoDB JSON 正是这些类型标签出错的地方——DynamoDB JSON 转换器在原生 JSON 与带类型标签的传输格式之间互转,而 DynoTable 桌面应用在编辑项目时会替你处理好 marshalling。

复现方法

在 boto3 期望 Key 映射的地方传一个字符串。这个检查完全发生在客户端:

import boto3
boto3.client('dynamodb', region_name='us-east-1').get_item(TableName='repro', Key='not-a-dict')

实际输出:

ParamValidationError: Parameter validation failed:
Invalid type for parameter Key, value: not-a-dict, type: <class 'str'>, valid types: <class 'dict'>

botocore 会点出参数、它收到的值、值的类型,以及它想要的类型——一条消息里四个事实。什么都没发给 AWS,所以没有消耗容量,也没有什么可重试的;修复点永远在调用处。

相关错误

参考资料

最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。

2026-07-26 针对 boto3 1.43.56 / botocore 1.43.56 复现——上方输出为原样照录。

无需控制台即可使用 DynamoDB

一款快速的 DynamoDB 桌面客户端,可运行 DynamoDB 无法执行的真正 SQL——JOINs、GROUP BY、聚合——并支持可视化编辑和运行在你自己的 Bedrock 密钥上的 AI agent。

30 天免费试用,无需信用卡 — 之后为无时间限制的免费版。