{"record":{"id":"8cadcd8926e81a55","repo":"hashicorp/terraform","slug":"not-all-parts-uploaded-successfully-multipart-upl","errorCode":null,"errorMessage":"not all parts uploaded successfully, multipart upload aborted","messagePattern":"not all parts uploaded successfully, multipart upload aborted","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oci/multipart_upload.go","lineNumber":147,"sourceCode":"\t\tcommitMultipartUploadPartDetails[i] = objectstorage.CommitMultipartUploadPartDetails{\n\t\t\tPartNum: common.Int(partNumber),\n\t\t\tEtag:    common.String(etag),\n\t\t}\n\t\ti++\n\t}\n\n\tif len(commitMultipartUploadPartDetails) != len(sourceBlocks) {\n\t\tabortReq := objectstorage.AbortMultipartUploadRequest{\n\t\t\tUploadId:      multipartUploadResponse.MultipartUpload.UploadId,\n\t\t\tNamespaceName: multipartUploadResponse.Namespace,\n\t\t\tBucketName:    multipartUploadResponse.Bucket,\n\t\t\tObjectName:    multipartUploadResponse.Object,\n\t\t}\n\t\t_, abortErr := multipartUploadData.client.objectStorageClient.AbortMultipartUpload(context.Background(), abortReq)\n\t\tif abortErr != nil {\n\t\t\tlogger.Error(fmt.Sprintf(\"Failed to abort multipart upload: %s\", abortErr))\n\t\t}\n\t\treturn fmt.Errorf(\"not all parts uploaded successfully, multipart upload aborted\")\n\t}\n\n\tcommitMultipartUploadRequest := objectstorage.CommitMultipartUploadRequest{\n\t\tUploadId:           multipartUploadResponse.MultipartUpload.UploadId,\n\t\tNamespaceName:      multipartUploadResponse.Namespace,\n\t\tBucketName:         multipartUploadResponse.Bucket,\n\t\tObjectName:         multipartUploadResponse.Object,\n\t\tOpcClientRequestId: multipartUploadResponse.OpcClientRequestId,\n\t\tRequestMetadata:    multipartUploadRequest.RequestMetadata,\n\t\tCommitMultipartUploadDetails: objectstorage.CommitMultipartUploadDetails{\n\t\t\tPartsToCommit: commitMultipartUploadPartDetails,\n\t\t},\n\t}\n\t_, err = multipartUploadData.client.objectStorageClient.CommitMultipartUpload(context.Background(), commitMultipartUploadRequest)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to commit multipart upload: %s\", err)\n\t}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/oci/multipart_upload.go#L129-L165","documentation":"A count check: if len(commitMultipartUploadPartDetails) != len(sourceBlocks), the code aborts the multipart upload and returns this error. The mismatch happens when one or more workers exited via errChan (sending a non-nil error) instead of pushing a response — so the responses channel has fewer entries than source blocks. Note: the per-worker error was already drained from errChan at lines 117-121 and would have returned earlier; reaching 318 means errChan was empty but responses were still short (e.g. a worker that errored AND the loop at 117 returned nil entries, or a worker that exited without sending to either channel on a panic).","triggerScenarios":"A worker that hit an error path which did not enqueue a response; a worker panic/recover gap; the errChan drain loop returned without error but responses are short due to channel ordering edge cases.","commonSituations":"Same root causes as 317 (per-part failures) but manifesting through the count-mismatch branch rather than the per-response check; concurrency edge cases in the worker channel protocol.","solutions":["Resolve underlying part-upload failures (see 317) — run with TF_LOG=DEBUG to find which worker errored.","Verify the abort succeeded — if AbortMultipartUpload itself failed, the log line 'Failed to abort multipart upload' appears; clean up uncommitted multipart uploads via bucket lifecycle rules.","Retry the Put once root causes are addressed.","Configure Object Storage bucket lifecycle to expire Incomplete/Uncommitted Multipart Uploads to avoid leaks from aborted uploads."],"exampleFix":"# before: aborted multipart uploads accumulate in the bucket after repeated 318\n# after: add a lifecycle rule to auto-expire uncommitted multipart uploads\noci os object-lifecycle-policy put --bucket-name tf-state --file lifecycle.json\n# lifecycle.json:\n# {\"items\":[{\"name\":\"expire-multipart\",\"action\":\"ABORT\",\"timeAmount\":1,\"timeUnit\":\"DAYS\",\"isEnabled\":true}]}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isMultipartAborted(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"multipart upload aborted\")\n}","tryCatchPattern":"// After an aborted multipart upload, confirm the abort succeeded before retrying\nif isMultipartAborted(err) {\n    // optionally list/abort any lingering uncommitted multipart uploads for the object\n    log.Println(\"[WARN] multipart upload aborted; verify bucket lifecycle cleans uncommitted uploads\")\n}","preventionTips":["Configure a bucket lifecycle rule to expire Incomplete/Uncommitted Multipart Uploads so aborted attempts do not leak storage.","Resolve per-part failures (see 317) before retrying the whole Put.","Run with TF_LOG=DEBUG to capture which worker exited early.","Alert on repeated multipart aborts as a signal of network/concurrency pressure."],"tags":["oci","multipart-upload","concurrency","cleanup"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}