{"record":{"id":"308f8d951b893317","repo":"hashicorp/terraform","slug":"failed-to-read-remote-state-s","errorCode":null,"errorMessage":"Failed to read remote state: %s","messagePattern":"Failed to read remote state: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/http/client.go","lineNumber":174,"sourceCode":"\t\t// Handled after\n\tcase http.StatusNoContent:\n\t\treturn nil, diags\n\tcase http.StatusNotFound:\n\t\treturn nil, diags\n\tcase http.StatusUnauthorized:\n\t\treturn nil, diags.Append(fmt.Errorf(\"HTTP remote state endpoint requires auth\"))\n\tcase http.StatusForbidden:\n\t\treturn nil, diags.Append(fmt.Errorf(\"HTTP remote state endpoint invalid auth\"))\n\tcase http.StatusInternalServerError:\n\t\treturn nil, diags.Append(fmt.Errorf(\"HTTP remote state internal server error\"))\n\tdefault:\n\t\treturn nil, diags.Append(fmt.Errorf(\"Unexpected HTTP response code %d\", resp.StatusCode))\n\t}\n\n\t// Read in the body\n\tbuf := bytes.NewBuffer(nil)\n\tif _, err := io.Copy(buf, resp.Body); err != nil {\n\t\treturn nil, diags.Append(fmt.Errorf(\"Failed to read remote state: %s\", err))\n\t}\n\n\t// Create the payload\n\tpayload := &remote.Payload{\n\t\tData: buf.Bytes(),\n\t}\n\n\t// If there was no data, then return nil\n\tif len(payload.Data) == 0 {\n\t\treturn nil, diags\n\t}\n\n\t// Check for the MD5\n\tif raw := resp.Header.Get(\"Content-MD5\"); raw != \"\" {\n\t\tmd5, err := base64.StdEncoding.DecodeString(raw)\n\t\tif err != nil {\n\t\t\treturn nil, diags.Append(fmt.Errorf(\n\t\t\t\t\"Failed to decode Content-MD5 '%s': %s\", raw, err))","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/http/client.go#L156-L192","documentation":"After the HTTP backend received an acceptable status code (200) for a Get(), reading the response body via io.Copy failed. This is a transport-level failure mid-stream rather than an HTTP protocol error; the underlying connection dropped or was reset while the body was being copied into a buffer.","triggerScenarios":"A GET to the state URL returns 200 but the connection is closed or reset before the full body is delivered, causing io.Copy(resp.Body) to return a non-nil error at client.go:173.","commonSituations":"An intermediary proxy/load balancer with a short read timeout cutting the connection on large state files; flaky network or VPN dropping packets; the state server crashing mid-response; TLS renegotiation or keep-alive closure during a long download.","solutions":["Retry the Terraform command; transient mid-stream resets usually succeed on the next attempt.","If recurring on large state, raise the read/idle timeouts on the reverse proxy in front of the state server.","Verify network stability to the state endpoint (large download test via curl).","Inspect TF_LOG=DEBUG output for the exact io error (e.g. 'connection reset by peer', 'unexpected EOF')."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Wrap remote-state reads and retry on transient io errors\nfor i := 0; i < 3; i++ {\n    payload, diags := client.Get()\n    if !diags.HasErrors() {\n        return payload, nil\n    }\n    // transient read errors (connection reset, EOF) are retryable\n    time.Sleep(backoff(i))\n}\nreturn nil, lastDiags","preventionTips":["Place the state server behind a proxy with read timeouts larger than the largest expected state download.","Prefer a managed object store (S3/GCS) over a hand-rolled HTTP endpoint for large states.","Monitor network stability between Terraform runners and the state endpoint."],"tags":["http","remote-state","network","io"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}