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
- 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.
- Verify update_method (default POST) matches what the endpoint accepts.
- For large states, raise nginx/proxy client_max_body_size or equivalent.
- 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
- Match update_method to what the endpoint supports (POST vs PUT).
- Set proxy/server body-size limits above your largest expected state.
- Acquire and pass the lock ID on writes when the endpoint enforces locking.
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
- Failed to read remote state
- failed to upload state
- failed to upload state
- address must be HTTP or HTTPS
- bucket not exists
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)