hashicorp/terraform · error

failed to upload part: %s

Error message

failed to upload part: %s

What it means

Raised while collecting worker responses in multiPartUploadImpl when an uploaded-part response is structurally invalid: response.error is set, or partNumber is nil, or response.response.ETag is nil. The commit phase needs both a part number and an ETag per part, so a response missing either cannot be committed. (Per-worker hard upload failures are instead reported via errChan as 'failed to upload part %d'.)

Source

Thrown at internal/backend/remote-state/oci/multipart_upload.go:126

			ctx.uploadPartsWorker()
		}()
	}

	wg.Wait()
	close(osUploadPartResponses)
	close(errChan)

	// Collect errors from workers
	for workerErr := range errChan {
		if workerErr != nil {
			return workerErr
		}
	}
	commitMultipartUploadPartDetails := make([]objectstorage.CommitMultipartUploadPartDetails, len(sourceBlocks))
	i := 0
	for response := range osUploadPartResponses {
		if response.error != nil || response.partNumber == nil || response.response.ETag == nil {
			return fmt.Errorf("failed to upload part: %s", response.error)
		}
		partNumber, etag := *response.partNumber, *response.response.ETag
		commitMultipartUploadPartDetails[i] = objectstorage.CommitMultipartUploadPartDetails{
			PartNum: common.Int(partNumber),
			Etag:    common.String(etag),
		}
		i++
	}

	if len(commitMultipartUploadPartDetails) != len(sourceBlocks) {
		abortReq := objectstorage.AbortMultipartUploadRequest{
			UploadId:      multipartUploadResponse.MultipartUpload.UploadId,
			NamespaceName: multipartUploadResponse.Namespace,
			BucketName:    multipartUploadResponse.Bucket,
			ObjectName:    multipartUploadResponse.Object,
		}
		_, abortErr := multipartUploadData.client.objectStorageClient.AbortMultipartUpload(context.Background(), abortReq)
		if abortErr != nil {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Re-run the apply; an anomalous missing-ETag response is usually transient.
  2. Check the OCI-SDK version (oci-go-sdk/v65) is current and compatible with the object storage service response shape.
  3. Capture the OpcRequestId of the offending UploadPart call from TF_LOG=TRACE to report to OCI support.
  4. If it recurs, fall back is automatic via client.Put (single-part) when size permits; otherwise reduce state size to avoid multipart.
Defensive patterns

Strategy: retry

Validate before calling

// No caller-side validation can prevent an anomalous missing-ETag response;
// ensure SDK version is current before relying on response shape.

Type guard

// Detect the structural defect after collection:
if response.error != nil || response.partNumber == nil || response.response.ETag == nil {
    // cannot commit this part
}

Try / catch

for response := range osUploadPartResponses {
    if response.error != nil || response.partNumber == nil || response.response.ETag == nil {
        return fmt.Errorf("failed to upload part: %s", response.error)
    }
    // ...
}

Prevention

When it happens

Trigger: Iterating osUploadPartResponses (multipart_upload.go:124) yields a response where response.error != nil, response.partNumber == nil, or response.response.ETag == nil — e.g. the OCI service accepted the UploadPart call but returned no ETag, or an SDK-level anomaly produced an incomplete response object.

Common situations: An OCI/SDK anomaly returning a 2xx UploadPart response with no ETag header; an unexpected response shape after an SDK upgrade; rare service hiccup that the retry policy did not smooth over.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/24599b29238a6e50. Report an issue: GitHub.