hashicorp/terraform · error

r.Status

Error message

r.Status

What it means

Fallback error in decodeErrorPayload (cloud/backend_common.go:758). When the response body cannot be JSON-decoded into jsonapi.ErrorsPayload, or decodes but contains zero errors, the function returns errors.New(r.Status) — i.e. the raw HTTP status line (e.g. '500 Internal Server Error'). This happens when TFE/HCP returns a non-JSON or empty error body.

Solutions

  1. Treat the bare status (e.g. 502/503/500) as a server/infrastructure problem and retry shortly.
  2. Verify the backend hostname points at the real TFE/HCP endpoint and no proxy is rewriting responses.
  3. Check TFE/HCP status page and server logs for the matching request.
Defensive patterns

Strategy: fallback

Type guard

func isRawHTTPStatus(err error) bool {
    // decodeErrorPayload falls back to errors.New(r.Status) when body is non-JSON.
    s := err.Error()
    return strings.HasSuffix(s, " Internal Server Error") ||
           strings.Contains(s, "Bad Gateway") || strings.Contains(s, "Service Unavailable")
}

Try / catch

err := callTFE()
if err != nil {
    if isRawHTTPStatus(err) { // body was empty/non-JSON → likely infra
        return retryWithBackoff()
    }
    return err
}

Prevention

When it happens

Trigger: A non-401/404 TFE/HCP API response whose body is empty, not valid JSON, or a JSON shape without an `errors` array — json.Decode fails or len(errPayload.Errors)==0, so the decoder falls back to r.Status.

Common situations: Reverse proxy/gateway returning an HTML error page (e.g. 502 from a load balancer). Server 5xx with empty body. Network middleware intercepting the request. Misconfigured hostname pointing at a non-TFE service.

Related errors


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

Appendix: source

Thrown at internal/cloud/backend_common.go:758

	case 404:
		return tfe.ErrResourceNotFound
	}

	errs, err = decodeErrorPayload(r)
	if err != nil {
		return err
	}

	return errors.New(strings.Join(errs, "\n"))
}

func decodeErrorPayload(r *http.Response) ([]string, error) {
	// Decode the error payload.
	var errs []string
	errPayload := &jsonapi.ErrorsPayload{}
	err := json.NewDecoder(r.Body).Decode(errPayload)
	if err != nil || len(errPayload.Errors) == 0 {
		return errs, errors.New(r.Status)
	}

	// Parse and format the errors.
	for _, e := range errPayload.Errors {
		if e.Detail == "" {
			errs = append(errs, e.Title)
		} else {
			errs = append(errs, fmt.Sprintf("%s\n\n%s", e.Title, e.Detail))
		}
	}

	return errs, nil
}

func isValidAppName(name string) bool {
	return name == "HCP Terraform" || name == "Terraform Enterprise"
}

View on GitHub (pinned to d32a084675)