hashicorp/terraform · error
failed to upload part %d: %w
Error message
failed to upload part %d: %w
What it means
Thrown by a worker goroutine inside multiPartUploadImpl when the OCI object storage UploadPart API call fails for a single chunk of a multipart upload. The %d is the 1-based part number and %w wraps the underlying SDK/network error. Because up to 10 concurrent workers run, one failing part aborts the whole upload via the worker returning early on the error channel.
Source
Thrown at internal/backend/remote-state/oci/multipart_upload.go:241
UploadPartBody: io.NopCloser(bytes.NewReader(buffer)),
UploadPartNum: block.blockNumber,
ContentMD5: common.String(base64.StdEncoding.EncodeToString(sum[:])),
RequestMetadata: common.RequestMetadata{
RetryPolicy: getDefaultRetryPolicy(),
},
}
if ctx.client.kmsKeyID != "" {
uploadPartRequest.OpcSseKmsKeyId = common.String(ctx.client.kmsKeyID)
} else if ctx.client.SSECustomerKey != "" && ctx.client.SSECustomerKeySHA256 != "" {
uploadPartRequest.OpcSseCustomerKey = common.String(ctx.client.SSECustomerKey)
uploadPartRequest.OpcSseCustomerKeySha256 = common.String(ctx.client.SSECustomerKeySHA256)
uploadPartRequest.OpcSseCustomerAlgorithm = common.String(ctx.client.SSECustomerAlgorithm)
}
response, err := ctx.client.objectStorageClient.UploadPart(context.Background(), *uploadPartRequest)
if err != nil {
ctx.errChan <- fmt.Errorf("failed to upload part %d: %w", *block.blockNumber, err)
return
}
ctx.osUploadPartResponses <- objectStorageUploadPartResponse{
response: response,
error: nil,
partNumber: block.blockNumber,
}
ctx.wg.Done()
}
}
View on GitHub (pinned to c9def3e214)
Solutions
- Inspect the wrapped error (the %w) — it is the real cause; fix that (auth, network, KMS key) before retrying.
- Verify the SSE settings: if the bucket uses a customer-provided key, ensure SSECustomerKey, SSECustomerKeySHA256 and SSECustomerAlgorithm are all set and consistent, or use kmsKeyId instead.
- Confirm the OCI credentials/region in the config are still valid and the namespace/bucket names are correct.
- Retry the operation on a stable network; the per-part request already carries getDefaultRetryPolicy() so transient blips are retried automatically — a surfaced error means retries were exhausted.
- If the file is near the 10000-part / 50GB-part limits, raise DefaultFilePartSize via the OSS client if the data is huge.
Example fix
// before: mismatched SSE config client.SSECustomerKey = key // SSECustomerKeySHA256 left unset -> part upload fails // after: provide the SHA256 (base64 of the raw key hash) consistently client.SSECustomerKey = key client.SSECustomerKeySHA256 = base64.StdEncoding.EncodeToString(sha256sum) client.SSECustomerAlgorithm = "AES256"
Defensive patterns
Strategy: retry
Validate before calling
// Before launching a large upload, confirm creds + SSE config are consistent.
func validateOCIClient(c *RemoteClient) error {
if c.bucketName == "" || c.namespace == "" {
return fmt.Errorf("oci client missing bucket/namespace")
}
if (c.SSECustomerKey != "") != (c.SSECustomerKeySHA256 != "") {
return fmt.Errorf("SSE-C requires both SSECustomerKey and SSECustomerKeySHA256")
}
return nil
} Try / catch
// Wrap multiPartUploadImpl; surface the wrapped part error, retry idempotently.
err := uploadData.multiPartUploadImpl(ctx)
if err != nil && strings.Contains(err.Error(), "failed to upload part") {
// part uploads are idempotent (ContentMD5 set); safe to retry the whole upload
return uploadData.multiPartUploadImpl(ctx)
} Prevention
- Keep SSE-C fields (key, sha256, algorithm) all set together or all empty.
- Use stable, low-latency connectivity for large state files.
- Refresh OCI tokens before long runs.
When it happens
Trigger: A call to multiPartUploadImpl whose source data exceeds 128MB (DefaultFilePartSize) so it is split into parts; UploadPart (oci objectstorage) returns a non-nil error for one chunk. Causes: expired STS/OAuth token, SSE-KMS/SSE-C key mismatch on a part, network reset mid-stream, bucket not found, quota/rate-limit, or ContentMD5 mismatch detected server-side.
Common situations: Running terraform init/apply with the oci backend on a large state file over an unstable link; rotating OCI credentials mid-run; specifying an SSECustomerKey that does not match the bucket's server-side encryption config; exceeding the object-storage request rate limit on a shared tenancy.
Related errors
- failed to access object '%s' in bucket '%s': %w
- unable to read 'content' from response: %w
- failed to read existing lock file content: %w
- consul lock was lost
- retrieving %s: %+v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/fc371d6669bdfdfd.
Report an issue: GitHub.