boto3: Parameter validation failed (ParamValidationError)

TL;DR — botocore.exceptions.ParamValidationError は、リクエストが送信される前に自分のマシン上で発生します — 渡した引数が、その操作の期待するシェイプと一致していません。DynamoDB のコードでは、ほぼ必ず client と resource の取り違えです。低レベルの client は DynamoDB JSON({'S': 'abc'}、数値は文字列)を求め、Table リソースはネイティブの 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 では捕まえられず、ネットワークのラウンドトリップも発生していません。メッセージは、失敗した正確なパラメータのパスと、期待していた型を名指しします。

発生する理由

  • 低レベルの client にネイティブの Python 値を渡しているboto3.client('dynamodb') は生の DynamoDB JSON を話します。すべての属性は型タグ付きのマップで、N の値は 文字列 です(42 ではなく {'N': '42'})。
  • Table リソースに DynamoDB JSON を渡している — 逆の取り違えです。boto3.resource('dynamodb').Table(...) はプレーンな Python の値を期待し、マーシャリングを代わりに行います。
  • 文字列が期待される場所に Condition オブジェクト — クエリのページネーターの KeyConditionExpression は文字列の式を受け取ります。そこに Key('pk').eq(...) オブジェクトを渡すと検証に失敗します。
  • タイプミスまたは非対応のパラメータ名 — 未知のキーは検証に失敗します。また古い botocore は、同梱モデルより後に API へ追加されたパラメータを拒否することがあります。

修正方法

  1. 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. ページネーターでは文字列の式を使いますKeyConditionExpression='pk = :p'ExpressionAttributeValues の組み合わせにするか、LastEvaluatedKey を使って Table リソースを手動でページングします。

  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 デスクトップアプリはマーシャリングを引き受けたうえでアイテムを編集させてくれます。

再現方法

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 は、パラメータ、受け取った値、その型、そして期待した型を名指しします — 1つのメッセージに4つの事実です。AWS には何も送信されていないので、キャパシティは消費されず、リトライすべきものもありません。修正は常に呼び出し側にあります。

関連するエラー

参考資料

最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

2026-07-26 に boto3 1.43.56 / botocore 1.43.56 で再現しました — 上記の出力はそのままの逐語です。

Console なしで DynamoDB を扱う

DynamoDB では実行できない本物の SQL(JOINs、GROUP BY、集計)を実行する高速な DynamoDB デスクトップクライアント。ビジュアル編集と、あなた自身の Bedrock キーで動く AI エージェントを備えています。

30日間無料トライアル、クレジットカード不要 — その後は期限のない Free プラン。