boto3: Parameter validation failed (ParamValidationError)

요약 — 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 값을 기대하며 마샬링은 대신 처리해 줍니다.
  • 문자열을 기대하는 곳에 조건 객체를 전달 — query 페이지네이터의 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. 페이지네이터에는 문자열 표현식을 쓰세요KeyConditionExpression='pk = :p'ExpressionAttributeValues를 조합하거나, Table 리소스를 LastEvaluatedKey로 직접 페이징하세요.

  3. 메시지의 파라미터 경로를 읽으세요Item.price.N은 어떤 속성의 어떤 타입 태그가 실패했는지 정확히 알려 줍니다. 추측하지 말고 그 필드를 고치세요.

  4. "Unknown parameter" 실패라면 botocore를 업그레이드하세요 — 파라미터는 실재하지만 검증 모델이 그보다 오래되었다면 pip install -U boto3 botocore.

  5. 서비스 오류와 따로 catch하세요:

    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는 파라미터, 받은 값, 그 타입, 기대한 타입까지 한 메시지에 네 가지 사실을 담아 줍니다. AWS로는 아무것도 전송되지 않았으므로 소비된 용량도 없고 재시도할 것도 없습니다. 해결은 언제나 호출 지점에서 이루어집니다.

관련 오류

참고 자료

위에 링크된 공식 AWS 문서를 기준으로 2026-07-13에 마지막으로 검증했습니다.

2026-07-26에 boto3 1.43.56 / botocore 1.43.56으로 재현했습니다 — 위 출력은 그대로 옮긴 것입니다.

Console 없이 DynamoDB 작업하기

DynamoDB로는 실행할 수 없는 진짜 SQL(JOINs, GROUP BY, 집계)을 실행하는 빠른 DynamoDB 데스크톱 클라이언트. 시각적 편집과 여러분 자신의 Bedrock 키로 동작하는 AI 에이전트를 제공합니다.

30일 무료 체험, 신용카드 불필요 — 이후 기간 제한 없는 무료 요금제.