hashicorp/terraform · error

failed to delete bucket

Error message

failed to delete bucket %v: %v

What it means

Returned by deleteBucket() when the COS SDK returns a nil response pointer from Bucket.Delete. The bucket-delete request never produced an HTTP response — transport-level failure. The original SDK error is wrapped.

Solutions

  1. Inspect the wrapped error and DEBUG line `deleteBucket <bucket>: error:`.
  2. Verify credentials and region/endpoint.
  3. Confirm outbound connectivity to COS.
  4. Retry after fixing the transport issue.

Example fix

// before: expired SecretKey causes DELETE to return nil response
export TENCENTCLOUD_SECRETKEY=expired
// after: rotate
export TENCENTCLOUD_SECRETKEY=fresh_key
Defensive patterns

Strategy: retry

Validate before calling

// Validate connectivity before attempting bucket delete
func canReachCOSForDelete(ctx context.Context, client *cos.Client, bucket string) error {
    rsp, err := client.Bucket.Delete(ctx)
    if rsp == nil { return fmt.Errorf("transport failure reaching COS to delete bucket %s: %w", bucket, err) }
    rsp.Body.Close()
    return nil
}

Type guard

func isDeleteBucketTransportFailure(rsp *cos.Response) bool { return rsp == nil }

Try / catch

// Retry nil-response bucket deletes as transport errors
backoff.Retry(func() error {
    rsp, err := client.Bucket.Delete(ctx)
    if rsp == nil { return err }
    defer rsp.Body.Close()
    if rsp.StatusCode == 404 { return nil }
    if err != nil { return backoff.Permanent(err) }
    return nil
}, backoff.NewExponentialBackOff())

Prevention

When it happens

Trigger: c.cosClient.Bucket.Delete(...) returns (nil, err). Network failure, invalid endpoint, missing/expired credentials, or context cancellation before any response.

Common situations: Same transport causes as 210/212: wrong region/endpoint, expired keys, no outbound connectivity, parent operation cancelled mid-destroy.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/ed1d51db28cd1498. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/cos/client.go:343

func (c *remoteClient) deleteBucket(recursive bool) error {
	if recursive {
		obs, err := c.getBucket("")
		if err != nil {
			if strings.Contains(err.Error(), "not exists") {
				return nil
			}
			log.Printf("[DEBUG] deleteBucket %s: empty bucket error: %v", c.bucket, err)
			return fmt.Errorf("failed to empty bucket %v: %v", c.bucket, err)
		}
		for _, v := range obs {
			c.deleteObject(v.Key)
		}
	}

	rsp, err := c.cosClient.Bucket.Delete(c.cosContext)
	if rsp == nil {
		log.Printf("[DEBUG] deleteBucket %s: error: %v", c.bucket, err)
		return fmt.Errorf("failed to delete bucket %v: %v", c.bucket, err)
	}
	defer rsp.Body.Close()

	log.Printf("[DEBUG] deleteBucket %s: code: %d, error: %v", c.bucket, rsp.StatusCode, err)
	if rsp.StatusCode == 404 {
		return nil
	}

	if err != nil {
		return fmt.Errorf("failed to delete bucket %v: %v", c.bucket, err)
	}

	return nil
}

// cosLock lock cos for writing
func (c *remoteClient) cosLock(bucket, cosFile string) error {
	log.Printf("[DEBUG] lock cos file %s:%s", bucket, cosFile)

View on GitHub (pinned to d32a084675)