hashicorp/terraform · error

HTTP error

Error message

HTTP error: %d

What it means

Thrown by Put() (upload state) when the POST/PUT response status is not 200/201/204 (client.go:236-242). The %d is the status code. This fires during terraform apply/destroy when writing the new state back to the HTTP endpoint.

Solutions

  1. Map the numeric code: 409 → force-unlock or wait for the other run; 413 → raise proxy/server body limit; 401/403 → fix auth; 405 → set the correct update_method.
  2. Verify update_method (default POST) matches what the endpoint accepts.
  3. For large states, raise nginx/proxy client_max_body_size or equivalent.
  4. Confirm the lock ID query parameter is being sent if the endpoint enforces locking.

Example fix

// before
backend "http" {
  address = "https://state.example.com/tf"
  # default update_method = "POST" but endpoint expects PUT
}
// after
backend "http" {
  address       = "https://state.example.com/tf"
  update_method = "PUT"
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check that the endpoint accepts the configured method and body size:
// req, _ := http.NewRequest(updateMethod, url, bytes.NewReader(sample))
// req.SetBasicAuth(user, pass); req.Header.Set("Content-Type","application/json")
// resp, _ := client.Do(req) // expect 200/201/204

Try / catch

// diags := httpClient.Put(data)
// for _, d := range diags {
//   if strings.Contains(d.Description().Summary, "HTTP error") {
//     code := parseCode(d.Description().Summary)
//     switch code { case 409: forceUnlockOrWait(); case 413: raiseBodyLimit() }
//   }
// }

Prevention

When it happens

Trigger: Upload returns 409 (lock held / conflict), 413 (payload too large), 401/403 (auth), 500 (server error), 405 (method not allowed), or any other non-2xx. Common during state push after a plan when the server rejects the write.

Common situations: State lock held by another run (409); reverse proxy body-size limit exceeded by a large state (413); wrong UpdateMethod configured (e.g., PUT against an endpoint expecting POST → 405); auth token expired between GET and PUT.

Related errors


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

Appendix: source

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

		}
	*/

	var method string = "POST"
	if c.UpdateMethod != "" {
		method = c.UpdateMethod
	}
	resp, err := c.httpRequest(method, &base, &data, "upload state")
	if err != nil {
		return diags.Append(err)
	}
	defer resp.Body.Close()

	// Handle the error codes
	switch resp.StatusCode {
	case http.StatusOK, http.StatusCreated, http.StatusNoContent:
		return diags
	default:
		return diags.Append(fmt.Errorf("HTTP error: %d", resp.StatusCode))
	}
}

func (c *httpClient) Delete() tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics

	// Make the request
	resp, err := c.httpRequest("DELETE", c.URL, nil, "delete state")
	if err != nil {
		return diags.Append(err)
	}
	defer resp.Body.Close()

	// Handle the error codes
	switch resp.StatusCode {
	case http.StatusOK:
		return diags
	default:

View on GitHub (pinned to d32a084675)