hashicorp/terraform · error
failed to commit multipart upload
Error message
failed to commit multipart upload: %s
What it means
The final CommitMultipartUpload call failed after all parts uploaded successfully. The object is not finalized. Notably, on this failure path the code does NOT call AbortMultipartUpload — the multipart upload is left open, which can leak storage until lifecycle rules clean it up.
Solutions
- Inspect the wrapped error's OCI code via errors.As(common.ServiceError) — OpcRequestId and code pinpoint the commit failure.
- Retry the whole Put once the root cause is addressed (the uncommitted multipart upload on the failed attempt will linger).
- Configure a bucket lifecycle rule to expire Incomplete/Uncommitted Multipart Uploads so failed commits do not leak storage.
- Consider patching the backend to call AbortMultipartUpload on this path (currently missing) to avoid manual cleanup.
Example fix
// before: commit fails, leaves an open multipart upload that leaks storage
// return fmt.Errorf("failed to commit multipart upload: %s", err)
// after: abort on commit failure to avoid leaking the upload
_, err = client.CommitMultipartUpload(ctx, commitReq)
if err != nil {
abortReq := objectstorage.AbortMultipartUploadRequest{
UploadId: multipartUploadResponse.MultipartUpload.UploadId,
NamespaceName: multipartUploadResponse.Namespace,
BucketName: multipartUploadResponse.Bucket,
ObjectName: multipartUploadResponse.Object,
}
_ = client.AbortMultipartUpload(ctx, abortReq)
return fmt.Errorf("failed to commit multipart upload: %s", err)
} Defensive patterns
Strategy: retry
Type guard
func isCommitError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to commit multipart upload")
} Try / catch
// On commit failure, abort the now-leaked multipart upload, then retry the Put
if err := commit(); err != nil {
_ = abortMultipartUpload(multipartUploadResponse) // currently missing in source
return fmt.Errorf("failed to commit multipart upload: %w", err)
} Prevention
- Patch the backend to call AbortMultipartUpload on the commit-failure path (currently missing) — it leaks the upload otherwise.
- Configure Object Storage lifecycle to expire Incomplete/Uncommitted Multipart Uploads automatically.
- Inspect the wrapped OCI error code to distinguish 4xx (config) from 5xx (retry).
- Refresh credentials before large uploads so the token survives until commit.
When it happens
Trigger: Commit API returned 4xx (wrong/missing part etag, part list misaligned) or 5xx (transient service failure, throttling); a part's ETag was stale by commit time; auth expired between upload and commit.
Common situations: Transient 5xx at commit; throttling under high concurrency; long uploads whose token expired before commit; mismatched part list after retries.
Related errors
- failed to upload part
- failed to upload part
- not all parts uploaded successfully, multipart upload…
- error creating multipart upload
- error reading source block
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/00e42de86a5ef8a3.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/oci/multipart_upload.go:163
logger.Error(fmt.Sprintf("Failed to abort multipart upload: %s", abortErr))
}
return fmt.Errorf("not all parts uploaded successfully, multipart upload aborted")
}
commitMultipartUploadRequest := objectstorage.CommitMultipartUploadRequest{
UploadId: multipartUploadResponse.MultipartUpload.UploadId,
NamespaceName: multipartUploadResponse.Namespace,
BucketName: multipartUploadResponse.Bucket,
ObjectName: multipartUploadResponse.Object,
OpcClientRequestId: multipartUploadResponse.OpcClientRequestId,
RequestMetadata: multipartUploadRequest.RequestMetadata,
CommitMultipartUploadDetails: objectstorage.CommitMultipartUploadDetails{
PartsToCommit: commitMultipartUploadPartDetails,
},
}
_, err = multipartUploadData.client.objectStorageClient.CommitMultipartUpload(context.Background(), commitMultipartUploadRequest)
if err != nil {
return fmt.Errorf("failed to commit multipart upload: %s", err)
}
return nil
}
func (m MultipartUploadData) objectMultiPartSplit() ([]objectStorageSourceBlock, error) {
dataSize := int64(len(m.Data))
offsets, partSize, err := SplitSizeToOffsetsAndLimits(dataSize)
if err != nil {
return nil, fmt.Errorf("error splitting data into parts: %s", err)
}
sourceBlocks := make([]objectStorageSourceBlock, len(offsets))
for i := range offsets {
start := offsets[i]
end := start + partSize
if end > dataSize {
end = dataSize
}
sourceBlocks[i] = objectStorageSourceBlock{View on GitHub (pinned to d32a084675)