hashicorp/terraform · error
failed to save file to %v: %v
Error message
failed to save file to %v: %v
What it means
Raised by putObject() when cosClient.Object.Put returns a nil response, meaning the HTTP request never produced a response object. The error wraps the underlying transport error. This path (rsp == nil) indicates the request failed before any COS response was received.
Source
Thrown at internal/backend/remote-state/cos/client.go:247
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
XCosMetaXXX: &http.Header{
"X-Cos-Meta-Md5": []string{fmt.Sprintf("%x", md5.Sum(data))},
},
},
ACLHeaderOptions: &cos.ACLHeaderOptions{
XCosACL: c.acl,
},
}
if c.encrypt {
opt.ObjectPutHeaderOptions.XCosServerSideEncryption = "AES256"
}
r := bytes.NewReader(data)
rsp, err := c.cosClient.Object.Put(c.cosContext, cosFile, r, opt)
if rsp == nil {
log.Printf("[DEBUG] putObject %s: error: %v", cosFile, err)
return fmt.Errorf("failed to save file to %v: %v", cosFile, err)
}
defer rsp.Body.Close()
log.Printf("[DEBUG] putObject %s: code: %d, error: %v", cosFile, rsp.StatusCode, err)
if err != nil {
return fmt.Errorf("failed to save file to %v: %v", cosFile, err)
}
return nil
}
// deleteObject delete remote object
func (c *remoteClient) deleteObject(cosFile string) error {
rsp, err := c.cosClient.Object.Delete(c.cosContext, cosFile)
if rsp == nil {
log.Printf("[DEBUG] deleteObject %s: error: %v", cosFile, err)
return fmt.Errorf("failed to delete file %v: %v", cosFile, err)
}View on GitHub (pinned to c9def3e214)
Solutions
- Verify network connectivity and DNS to the bucket endpoint: 'curl -I https://<bucket>.cos.<region>.myqcloud.com'.
- Confirm the bucket name and region in the backend block match the actual COS bucket.
- Check that the Tencent Cloud credentials (SecretId/SecretKey/SecurityToken) are valid and not expired, and that the COS/Tag STS scope covers object writes.
- Retry the apply — transient transport errors frequently clear on the next attempt.
Example fix
# verify endpoint reachability and credentials curl -I https://tf-state-1234567890.cos.ap-guangzhou.myqcloud.com # check region/bucket name in the backend block terraform init -backend=false
Defensive patterns
Strategy: retry
Validate before calling
// Preflight: confirm the endpoint resolves and credentials work.
func cosReachable(ctx context.Context, endpoint string) error {
req, _ := http.NewRequestWithContext(ctx, "HEAD", endpoint, nil)
_, err := http.DefaultClient.Do(req)
return err
} Try / catch
if err := c.putObject(c.stateFile, data); err != nil {
if strings.Contains(err.Error(), "failed to save file to") {
// transport-level; safe to retry the Put
}
} Prevention
- Validate bucket name/region in the backend block before init.
- Run from a host with reliable egress to cos.*.myqcloud.com.
- Keep credentials fresh (rotate STS before expiry).
When it happens
Trigger: At client.go:244-247, the Put call returns (nil, err). Occurs on DNS resolution failure, connection refused, TLS handshake error, context cancellation before the request was sent, or the SDK's internal retry budget being exhausted with no successful response.
Common situations: Wrong region/endpoint in the backend config (bucket URL typo); network outage or firewall blocking egress to cos.*.myqcloud.com; expired/invalid SecretId/SecretKey causing auth-layer failure before a response; VPN/proxy dropping the connection; terraform killed (Ctrl-C) during the write.
Related errors
- failed to delete file %v: %v
- failed to delete bucket %v: %v
- bucket %s not exists
- failed to create bucket %v: %v
- failed to open file at %v: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/615d3e15ad41daf0.
Report an issue: GitHub.