apache/flink · error · IOException
Failed to complete multipart upload for key: {}
Error message
Failed to complete multipart upload for key: {} What it means
completeMultipartUpload() catches NoSuchUploadException and, as a recovery heuristic, checks whether the object already exists (getObjectMetadata) — the upload may have been completed by a previous attempt before a failover. If that existence check ALSO fails (object absent), this IOException is thrown wrapping the ORIGINAL NoSuchUploadException: the upload is gone and there is no committed object, so the write is genuinely lost from this handle's perspective. This is the failure that indicates an aborted/expired upload rather than a completed one.
Source
Thrown at flink-filesystems/flink-s3-fs-native/src/main/java/org/apache/flink/fs/s3native/writer/NativeS3ObjectOperations.java:336
CompleteMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.multipartUpload(
CompletedMultipartUpload.builder()
.parts(completedParts)
.build())
.build();
CompleteMultipartUploadResponse response = s3Client.completeMultipartUpload(request);
return new CompleteMultipartUploadResult(
bucketName, key, response.eTag(), response.location());
} catch (NoSuchUploadException e) {
try {
ObjectMetadata metadata = getObjectMetadata(key);
return new CompleteMultipartUploadResult(bucketName, key, metadata.getETag(), null);
} catch (IOException checkEx) {
throw new IOException("Failed to complete multipart upload for key: " + key, e);
}
} catch (S3Exception e) {
throw new IOException("Failed to complete multipart upload for key: " + key, e);
}
}
public void abortMultiPartUpload(String key, String uploadId) throws IOException {
try {
AbortMultipartUploadRequest request =
AbortMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.build();
s3Client.abortMultipartUpload(request);
} catch (S3Exception e) {
throw new IOException(View on GitHub (pinned to 2f3c205e92)
Solutions
- Ensure exactly one committer per upload: rely on Flink's exactly-once committer semantics / FileSink committer rather than calling commit() from multiple recovered attempts.
- Review bucket lifecycle AbortIncompleteMultipartUpload days vs your longest expected recovery window; raise it above your max checkpoint/savepoint restore delay.
- Examine the cause: NoSuchUpload + missing object means this write must be redone — re-run from the last good checkpoint (data since the upload start is not recoverable from this handle).
- Audit external automation that aborts multipart uploads or deletes objects in the target prefix.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before committing a recovered upload, confirm it is still live
try {
s3Client.listMultipartUploads(b -> b.bucket(bucket).prefix(key));
// if uploadId absent from listing AND object absent via headObject -> upload lost: plan re-write
} catch (S3Exception e) { /* surface config/permission problem early */ } Try / catch
catch (IOException e) { if (e.getCause() instanceof NoSuchUploadException) { // upload aborted/expired and object absent -> data must be re-written from last checkpoint; never retry this commit } else throw e; } Prevention
- Set bucket lifecycle AbortIncompleteMultipartUpload above your worst-case recovery time.
- Guarantee a single committer per upload (Flink committable semantics) so attempts never abort each other.
- Keep checkpoint intervals short enough that recovered uploads commit well inside any lifecycle window.
When it happens
Trigger: Multipart upload aborted by another attempt (duplicate committer after recovery), aborted by an S3 lifecycle rule (AbortIncompleteMultipartUpload), uploadId expired, or the complete succeeded on a previous attempt but the object was since deleted — then getObjectMetadata throws and this error surfaces with the NoSuchUpload cause.
Common situations: Two committers racing after task failover (one aborts, one completes); bucket lifecycle rules aggressively cleaning incomplete uploads (e.g. 1 day) while jobs hold recoverable state longer; user/scripts deleting objects mid-recovery; cross-run dedup logic aborting 'stale' uploads it should not have.
Related errors
- Error recovering writer: Downloading the last data chunk fil
- Cannot commit empty multipart upload for object: {}. This in
- Failed to start multipart upload for key: {}
- Failed to upload part %d for key: %s, uploadId: %s
- Failed to abort multipart upload for key: %s, uploadId: %s
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/70b39dfb0a0faf4d.
Report an issue: GitHub.