hashicorp/terraform · error

Failed to make HTTP request

Error message

Failed to make %s HTTP request: %s

What it means

retryablehttp.NewRequest(method, url, body) returned an error before any network call. This is a request-construction failure, almost always an invalid HTTP method (containing spaces or control characters) or, less often, an invalid URL string with control characters. The '%s' is filled by the 'what' argument: 'lock', 'unlock', 'get state', 'upload state', or 'delete state'.

Solutions

  1. Set update_method/lock_method/unlock_method to a valid HTTP verb with no whitespace (POST, PUT, LOCK, UNLOCK, DELETE, GET).
  2. Trim trailing newlines/whitespace from the TF_HTTP_*_METHOD env vars: export TF_HTTP_LOCK_METHOD=$(printf '%s' "$TF_HTTP_LOCK_METHOD").
  3. Re-run terraform init after correcting the method value.

Example fix

// before (env has trailing newline)
//   TF_HTTP_LOCK_METHOD='LOCK\n'
// after
export TF_HTTP_LOCK_METHOD=LOCK
Defensive patterns

Strategy: validation

Validate before calling

# Pre-flight: HTTP methods must be a bare token with no whitespace/control chars
for v in TF_HTTP_UPDATE_METHOD TF_HTTP_LOCK_METHOD TF_HTTP_UNLOCK_METHOD; do
  val=$(eval echo "\$$v")
  if [ -n "$val" ] && printf '%s' "$val" | grep -Pq '[\x00-\x20]|[^[:print:]]'; then
    echo "ERROR: $v contains whitespace/control chars: '$val'"; exit 1
  fi
done

Prevention

When it happens

Trigger: User set lock_method/unlock_method/update_method to a string containing whitespace or control characters (e.g. 'LOCK\n', 'P OST'); a URL string contains control characters that slipped past url.Parse at config time (very rare).

Common situations: Env var (TF_HTTP_LOCK_METHOD etc.) carries a trailing newline from a secret store or echo; method mistyped with a space; method set via a variable that picked up whitespace.

Related errors


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

Appendix: source

Thrown at internal/backend/remote-state/http/client.go:53

	Client   *retryablehttp.Client
	Username string
	Password string

	lockID       string
	jsonLockInfo []byte
}

func (c *httpClient) httpRequest(method string, url *url.URL, data *[]byte, what string) (*http.Response, error) {
	// If we have data we need a reader
	var reader io.Reader = nil
	if data != nil {
		reader = bytes.NewReader(*data)
	}

	// Create the request
	req, err := retryablehttp.NewRequest(method, url.String(), reader)
	if err != nil {
		return nil, fmt.Errorf("Failed to make %s HTTP request: %s", what, err)
	}
	// Set up basic auth
	if c.Username != "" {
		req.SetBasicAuth(c.Username, c.Password)
	}

	// Work with data/body
	if data != nil {
		req.Header.Set("Content-Type", "application/json")
		req.ContentLength = int64(len(*data))

		// Generate the MD5
		hash := md5.Sum(*data)
		b64 := base64.StdEncoding.EncodeToString(hash[:])
		req.Header.Set("Content-MD5", b64)
	}

	// Make the request

View on GitHub (pinned to d32a084675)