apache/beam · error · S3ClientError

Param validation failed on part number

Error message

Param validation failed on part number

What it means

FakeS3Client.upload_part raises S3ClientError('Param validation failed on part number', 400) when the request's part_number is not an int or is negative. It stands in for boto3's client-side parameter validation (ParamValidationError) for multipart upload part numbers.

Solutions

  1. Ensure part numbers are plain Python ints and >= 0 (S3 uses 1-based part numbers, so start at 1)
  2. Cast: part_number = int(part_number) before building the request
  3. Add an assert/validate on part_number type and range before calling upload_part
  4. Fix off-by-one or 0-based indexing logic in the uploader

Example fix

// before
request = messages.UploadPartRequest(upload_id, i, data)  # i may be negative or numpy int
// after
part_number = int(i)
if part_number < 1:
    raise ValueError(f'invalid part number: {part_number}')
request = messages.UploadPartRequest(upload_id, part_number, data)
Defensive patterns

Strategy: validation

Validate before calling

assert isinstance(part_number, int) and not isinstance(part_number, bool) and part_number >= 0, f'bad part number: {part_number!r}'

Prevention

When it happens

Trigger: Calling upload_part with part_number < 0, a bool/float/str/None part_number, or a numpy integer type that fails isinstance(part_number, int).

Common situations: Loop index off-by-one producing negative numbers; part numbers computed from data (0-based vs 1-based confusion); passing a numpy.int64 from array-based code paths.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/c19f59bdaf21dd51. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/io/aws/clients/s3/fake_client.py:192

    src_file = self.get_file(request.src_bucket, request.src_key)
    dest_file = FakeFile(
        request.dest_bucket, request.dest_key, src_file.contents)
    self.add_file(dest_file)

  def create_multipart_upload(self, request):
    # Create hash of bucket and key
    # Store upload_id internally
    upload_id = request.bucket + request.object
    self.multipart_uploads[upload_id] = {}
    return messages.UploadResponse(upload_id)

  def upload_part(self, request):
    # Save off bytes passed to internal data store
    upload_id, part_number = request.upload_id, request.part_number

    if part_number < 0 or not isinstance(part_number, int):
      raise messages.S3ClientError(
          'Param validation failed on part number', 400)

    if upload_id not in self.multipart_uploads:
      raise messages.S3ClientError('The specified upload does not exist', 404)

    self.multipart_uploads[upload_id][part_number] = request.bytes

    etag = '"%s"' % ('x' * 32)
    return messages.UploadPartResponse(etag, part_number)

  def complete_multipart_upload(self, request):
    MIN_PART_SIZE = 5 * 2**10  # 5 KiB

    parts_received = self.multipart_uploads[request.upload_id]

    # Check that we got all the parts that they intended to send
    part_numbers_to_confirm = set(part['PartNumber'] for part in request.parts)

View on GitHub (pinned to 12126d8942)