{"record":{"id":"5c09420ecd1945f5","repo":"hashicorp/terraform","slug":"failed-to-read-the-body-of-the-s3-object-w","errorCode":null,"errorMessage":"failed to read the body of the S3 object: %w","messagePattern":"failed to read the body of the S3 object: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/s3/client.go","lineNumber":532,"sourceCode":"\tif c.serverSideEncryption && c.customerEncryptionKey != nil {\n\t\tgetInput.SSECustomerKey = aws.String(base64.StdEncoding.EncodeToString(c.customerEncryptionKey))\n\t\tgetInput.SSECustomerAlgorithm = aws.String(s3EncryptionAlgorithm)\n\t\tgetInput.SSECustomerKeyMD5 = aws.String(c.getSSECustomerKeyMD5())\n\t}\n\n\tgetOutput, err := c.s3Client.GetObject(ctx, getInput)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to retrieve file from S3 bucket '%s' with key '%s': %w\", c.bucketName, c.lockFilePath, err)\n\t}\n\tdefer func() {\n\t\tif cerr := getOutput.Body.Close(); cerr != nil {\n\t\t\tlog.Warn(fmt.Sprintf(\"failed to close S3 object body: %v\", cerr))\n\t\t}\n\t}()\n\n\tdata, err := io.ReadAll(getOutput.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read the body of the S3 object: %w\", err)\n\t}\n\n\tlockInfo := &statemgr.LockInfo{}\n\tif err := json.Unmarshal(data, lockInfo); err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal JSON data into LockInfo struct: %w\", err)\n\t}\n\tlockErr.Info = lockInfo\n\n\t// Verify that the provided lock ID matches the lock ID of the retrieved lock file.\n\tif lockInfo.ID != id {\n\t\treturn fmt.Errorf(\"lock ID '%s' does not match the existing lock ID '%s'\", id, lockInfo.ID)\n\t}\n\n\t// Delete the lock file to release the lock.\n\t_, err = c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{\n\t\tBucket: aws.String(c.bucketName),\n\t\tKey:    aws.String(c.lockFilePath),\n\t})","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/s3/client.go#L514-L550","documentation":"Returned by unlockWithFile when S3 GetObject succeeded but io.ReadAll on the response body fails. The same message literal is emitted on this single line (line 532); the duplicate index is because the analyzer captured the same site twice. The body stream is the JSON-encoded LockInfo for the .tflock file.","triggerScenarios":"Calling Unlock -> unlockWithFile where c.s3Client.GetObject returns a 200 response but reading from getOutput.Body errors: connection reset mid-stream, socket timeout, truncated response, or an SDK reader returning an unexpected EOF.","commonSituations":"Flaky network between the runner and S3; object larger than expected or corrupted; SDK version with a streaming bug; object stored with an incompatible content-encoding.","solutions":["Retry the unlock operation — body-read failures are usually transient.","If persistent, download the object manually to verify it is readable and not corrupted.","Check SDK and HTTP client timeouts; raise them if the runner has high latency to S3.","Recreate the lock file if the stored object is corrupt."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry transient body-read failures with backoff\nvar data []byte\nerr := backoff.Retry(func() error {\n    out, e := s3c.GetObject(ctx, &s3.GetObjectInput{Bucket: &bucket, Key: &lockKey})\n    if e != nil { return e }\n    defer out.Body.Close()\n    data, e = io.ReadAll(out.Body)\n    return e\n}, backoff.NewExponentialBackOff())","preventionTips":["Wrap unlock in an exponential-backoff retry for transient stream errors.","Tune HTTP client timeouts for high-latency runner-to-S3 paths.","Use S3 VPC endpoints in private subnets for stable throughput.","Monitor for frequent resets and rotate the network path if needed."],"tags":["s3","io","network","terraform-state","locking"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}