{"record":{"id":"5a1b40a115029231","repo":"apache/beam","slug":"all-parts-but-the-last-must-be-larger-than-d-bytes","errorCode":null,"errorMessage":"All parts but the last must be larger than %d bytes","messagePattern":"All parts but the last must be larger than (.+?) bytes","errorType":"validation","errorClass":"S3ClientError","httpStatus":400,"severity":"error","filePath":"sdks/python/apache_beam/io/aws/clients/s3/fake_client.py","lineNumber":226,"sourceCode":"    # 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\n    # Make sure all the expected parts are present\n    if part_numbers_to_confirm != set(parts_received.keys()):\n      raise messages.S3ClientError(\n          'One or more of the specified parts could not be found', 400)\n\n    # Sort by part number\n    sorted_parts = sorted(parts_received.items(), key=lambda pair: pair[0])\n    sorted_bytes = [bytes_ for (_, bytes_) in sorted_parts]\n\n    # Make sure that the parts aren't too small (except the last part)\n    part_sizes = [len(bytes_) for bytes_ in sorted_bytes]\n    if any(size < MIN_PART_SIZE for size in part_sizes[:-1]):\n      e_message = \"\"\"\n      All parts but the last must be larger than %d bytes\n      \"\"\" % MIN_PART_SIZE\n      raise messages.S3ClientError(e_message, 400)\n\n    # String together all bytes for the given upload\n    final_contents = b''.join(sorted_bytes)\n\n    # Create FakeFile object\n    num_parts = len(parts_received)\n    etag = '\"%s-%d\"' % ('x' * 32, num_parts)\n    file_ = FakeFile(request.bucket, request.object, final_contents, etag=etag)\n\n    # Store FakeFile in self.files\n    self.add_file(file_)\n","sourceCodeStart":208,"sourceCodeEnd":238,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/aws/clients/s3/fake_client.py#L208-L238","documentation":"FakeS3Client.complete_multipart_upload raises S3ClientError('All parts but the last must be larger than MIN_PART_SIZE bytes', 400) when any non-final part is smaller than the minimum part size (5 MiB in real S3). It mirrors S3's EntityTooSmall error.","triggerScenarios":"Completing a multipart upload where any part except the last has len(bytes) < MIN_PART_SIZE, typically because data was chunked too finely.","commonSituations":"Small test datasets split into too many tiny parts; a chunk-size configuration set below 5 MiB; merging logic that splits on record boundaries producing small shards.","solutions":["Increase the chunk size so every part except the last is >= MIN_PART_SIZE (5 MiB)","Merge undersized parts together before completing the upload","Use fewer parts for small datasets, or skip multipart for small payloads","Adjust MIN_PART_SIZE in the fake only for tiny test fixtures, acknowledging the divergence from real S3"],"exampleFix":"// before\nparts = [data[i:i+1024*1024] for i in range(0, len(data), 1024*1024)]  # 1 MiB < 5 MiB min\n// after\nMIN_PART_SIZE = 5 * 1024 * 1024\nparts = [data[i:i+MIN_PART_SIZE] for i in range(0, len(data), MIN_PART_SIZE)]","handlingStrategy":"validation","validationCode":"sizes = [len(p) for p in parts]\nassert all(s >= fake_client.MIN_PART_SIZE for s in sizes[:-1]), f'undersized non-final parts: {sizes}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a chunk size >= 5 MiB for all but the last part","Merge small parts before completing the upload","Skip multipart entirely for small payloads","Account for MIN_PART_SIZE when generating test data"],"tags":["aws","s3","multipart-upload","size-limit"],"backgroundTag":"file-size-limit-exceeded","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"}