hashicorp/terraform · error

server returned unsuccessful status %d

Error message

server returned unsuccessful status %d

What it means

Inside AvailableVersions, after handling 200/404/401/403 explicitly, any other status code from the mirror's index.json request is reported via errQueryFailed with this message. It covers server-side failures (5xx) and unexpected 2xx/3xx that slipped through. Returned wrapped as ErrQueryFailed.

Source

Thrown at internal/getproviders/http_mirror_source.go:137

		if body != nil {
			body.Close()
		}
	}()
	if err != nil {
		return nil, nil, s.errQueryFailed(provider, err)
	}

	switch statusCode {
	case http.StatusOK:
		// Great!
	case http.StatusNotFound:
		return nil, nil, ErrProviderNotFound{
			Provider: provider,
		}
	case http.StatusUnauthorized, http.StatusForbidden:
		return nil, nil, s.errUnauthorized(finalURL)
	default:
		return nil, nil, s.errQueryFailed(provider, fmt.Errorf("server returned unsuccessful status %d", statusCode))
	}

	// If we got here then the response had status OK and so our body
	// will be non-nil and should contain some JSON for us to parse.
	var bodyContent ListVersionsResponseBody

	dec := json.NewDecoder(body)
	if err := dec.Decode(&bodyContent); err != nil {
		return nil, nil, s.errQueryFailed(provider, fmt.Errorf("invalid response content from mirror server: %s", err))
	}

	if len(bodyContent.Versions) == 0 {
		return nil, nil, nil
	}
	ret := make(VersionList, 0, len(bodyContent.Versions))
	for versionStr := range bodyContent.Versions {
		version, err := ParseVersion(versionStr)
		if err != nil {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Retry the operation after a short backoff — 5xx/429 are often transient.
  2. Check the mirror service health and logs for the failing path.
  3. If 429, raise rate limits or stagger concurrent terraform runs against the mirror.

Example fix

// before
vers, _, err := mirror.AvailableVersions(ctx, p)
if err != nil { return err } // surfaces "server returned unsuccessful status 503"

// after
vers, _, err := retryOn5xx(ctx, func() (getproviders.VersionList, getproviders.Warnings, error) {
    return mirror.AvailableVersions(ctx, p)
})
Defensive patterns

Strategy: retry

Try / catch

var qf getproviders.ErrQueryFailed
if errors.As(err, &qf) {
    // qf.Wrapped holds the inner "server returned unsuccessful status N" error;
    // retry with exponential backoff for transient (5xx/429) statuses
}

Prevention

When it happens

Trigger: GET <host>/<ns>/<type>/index.json returns 500, 502, 503, 504, 429, or another non-handled status. Happens when the mirror is overloaded, a gateway errors, or an auth-adjacent filter returns 401-like behavior as a different code.

Common situations: Mirror behind a flaky gateway; rate limiting (429) from a shared mirror; transient backend outage during terraform init.

Related errors


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