{"record":{"id":"c19f59bdaf21dd51","repo":"apache/beam","slug":"param-validation-failed-on-part-number","errorCode":null,"errorMessage":"Param validation failed on part number","messagePattern":"Param validation failed on part number","errorType":"validation","errorClass":"S3ClientError","httpStatus":400,"severity":"error","filePath":"sdks/python/apache_beam/io/aws/clients/s3/fake_client.py","lineNumber":192,"sourceCode":"\n    src_file = self.get_file(request.src_bucket, request.src_key)\n    dest_file = FakeFile(\n        request.dest_bucket, request.dest_key, src_file.contents)\n    self.add_file(dest_file)\n\n  def create_multipart_upload(self, request):\n    # Create hash of bucket and key\n    # Store upload_id internally\n    upload_id = request.bucket + request.object\n    self.multipart_uploads[upload_id] = {}\n    return messages.UploadResponse(upload_id)\n\n  def upload_part(self, request):\n    # Save off bytes passed to internal data store\n    upload_id, part_number = request.upload_id, request.part_number\n\n    if part_number < 0 or not isinstance(part_number, int):\n      raise messages.S3ClientError(\n          'Param validation failed on part number', 400)\n\n    if upload_id not in self.multipart_uploads:\n      raise messages.S3ClientError('The specified upload does not exist', 404)\n\n    self.multipart_uploads[upload_id][part_number] = request.bytes\n\n    etag = '\"%s\"' % ('x' * 32)\n    return messages.UploadPartResponse(etag, part_number)\n\n  def complete_multipart_upload(self, request):\n    MIN_PART_SIZE = 5 * 2**10  # 5 KiB\n\n    parts_received = self.multipart_uploads[request.upload_id]\n\n    # Check that we got all the parts that they intended to send\n    part_numbers_to_confirm = set(part['PartNumber'] for part in request.parts)\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/aws/clients/s3/fake_client.py#L174-L210","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure part numbers are plain Python ints and >= 0 (S3 uses 1-based part numbers, so start at 1)","Cast: part_number = int(part_number) before building the request","Add an assert/validate on part_number type and range before calling upload_part","Fix off-by-one or 0-based indexing logic in the uploader"],"exampleFix":"// before\nrequest = messages.UploadPartRequest(upload_id, i, data)  # i may be negative or numpy int\n// after\npart_number = int(i)\nif part_number < 1:\n    raise ValueError(f'invalid part number: {part_number}')\nrequest = messages.UploadPartRequest(upload_id, part_number, data)","handlingStrategy":"validation","validationCode":"assert isinstance(part_number, int) and not isinstance(part_number, bool) and part_number >= 0, f'bad part number: {part_number!r}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use 1-based, plain-int part numbers (S3 convention)","Cast indices with int() before building requests","Beware numpy integers failing isinstance(x, int)","Add a unit assertion on part_number range in upload loops"],"tags":["aws","s3","multipart-upload","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}