The bug was using size (remaining bytes) instead of length (actual part size) when constructing PartInfo in the multipart copy loop. This would record wrong sizes for each part - especially problematic for the last part.