hashicorp/terraform · error

the request failed after %d attempts, please try again later

Error message

the request failed after %d attempts, please try again later%s

What it means

maxRetryErrorHandler is the terminal handler for go-retryablehttp when all retry attempts are used up and numTries > 1. It reports how many attempts were made plus the last status or transport error. Default discoveryRetry is 1, so under normal config this is the common 'retries exhausted' terminal error for retryable failures (5xx, network).

Source

Thrown at internal/getproviders/registry_client.go:490

	// Close the body per library instructions
	if resp != nil {
		resp.Body.Close()
	}

	// Additional error detail: if we have a response, use the status code;
	// if we have an error, use that; otherwise nothing. We will never have
	// both response and error.
	var errMsg string
	if resp != nil {
		errMsg = fmt.Sprintf(": %s returned from %s", resp.Status, HostFromRequest(resp.Request))
	} else if err != nil {
		errMsg = fmt.Sprintf(": %s", err)
	}

	// This function is always called with numTries=RetryMax+1. If we made any
	// retry attempts, include that in the error message.
	if numTries > 1 {
		return resp, fmt.Errorf("the request failed after %d attempts, please try again later%s",
			numTries, errMsg)
	}
	return resp, fmt.Errorf("the request failed, please try again later%s", errMsg)
}

// HostFromRequest extracts host the same way net/http Request.Write would,
// accounting for empty Request.Host
func HostFromRequest(req *http.Request) string {
	if req.Host != "" {
		return req.Host
	}
	if req.URL != nil {
		return req.URL.Host
	}

	// this should never happen and if it does
	// it will be handled as part of Request.Write()
	// https://cs.opensource.google/go/go/+/refs/tags/go1.18.4:src/net/http/request.go;l=574

View on GitHub (pinned to c9def3e214)

Solutions

  1. Retry terraform init later — the failure is usually transient.
  2. Increase TF_REGISTRY_DISCOVERY_RETRY (e.g. 3-5) to survive longer outages.
  3. Increase TF_REGISTRY_CLIENT_TIMEOUT to avoid timeout-induced retry exhaustion.
  4. Check connectivity to the registry host and any proxy (HTTPS_PROXY).
  5. If a private registry, investigate its logs for the 5xx.

Example fix

# before
export TF_REGISTRY_DISCOVERY_RETRY=1
export TF_REGISTRY_CLIENT_TIMEOUT=10
# after
export TF_REGISTRY_DISCOVERY_RETRY=5
export TF_REGISTRY_CLIENT_TIMEOUT=30
Defensive patterns

Strategy: retry

Try / catch

// Wrap the registry call; retryable exhaustion is transient.
func withRetry(ctx context.Context, fn func() error) error {
    var err error
    for i := 0; i < 3; i++ {
        if err = fn(); err == nil {
            return nil
        }
        if !strings.Contains(err.Error(), "please try again later") {
            return err
        }
        select {
        case <-time.After(time.Duration(i+1) * time.Second):
        case <-ctx.Done():
            return ctx.Err()
        }
    }
    return err
}

Prevention

When it happens

Trigger: A retryable registry failure (5xx, network timeout, connection reset) persisted across all attempts. numTries equals RetryMax+1 (RetryMax from TF_REGISTRY_DISCOVERY_RETRY, default 1 -> 2 attempts).

Common situations: Registry or CDN transient outage; corporate proxy intermittently dropping connections; DNS flakiness; TF_REGISTRY_CLIENT_TIMEOUT too short causing repeated timeouts that exhaust retries; rate limiting (429) treated as retryable by the underlying library.

Related errors


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