{"record":{"id":"55936ae3b16545a1","repo":"hashicorp/terraform","slug":"failed-to-open-file-at-v-checksum-s-invalid","errorCode":null,"errorMessage":"failed to open file at %v: checksum %s invalid","messagePattern":"failed to open file at (.+?): checksum (.+?) invalid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/cos/client.go","lineNumber":204,"sourceCode":"\t\terr = fmt.Errorf(\"failed to open file at %v: %v\", cosFile, err)\n\t\treturn\n\t}\n\tdefer rsp.Body.Close()\n\n\tlog.Printf(\"[DEBUG] getObject %s: code: %d, error: %v\", cosFile, rsp.StatusCode, err)\n\tif err != nil {\n\t\tif rsp.StatusCode == 404 {\n\t\t\terr = nil\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"failed to open file at %v: %v\", cosFile, err)\n\t\t}\n\t\treturn\n\t}\n\n\tchecksum = rsp.Header.Get(\"X-Cos-Meta-Md5\")\n\tlog.Printf(\"[DEBUG] getObject %s: checksum: %s\", cosFile, checksum)\n\tif len(checksum) != 32 {\n\t\terr = fmt.Errorf(\"failed to open file at %v: checksum %s invalid\", cosFile, checksum)\n\t\treturn\n\t}\n\n\texists = true\n\tdata, err = ioutil.ReadAll(rsp.Body)\n\tlog.Printf(\"[DEBUG] getObject %s: data length: %d\", cosFile, len(data))\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed to open file at %v: %v\", cosFile, err)\n\t\treturn\n\t}\n\n\tcheck := fmt.Sprintf(\"%x\", md5.Sum(data))\n\tlog.Printf(\"[DEBUG] getObject %s: check: %s\", cosFile, check)\n\tif check != checksum {\n\t\terr = fmt.Errorf(\"failed to open file at %v: checksum mismatch, %s != %s\", cosFile, check, checksum)\n\t\treturn\n\t}\n","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/cos/client.go#L186-L222","documentation":"Thrown by getObject() when the returned object has no valid MD5 checksum metadata. The COS backend stores a 32-char hex MD5 in the `X-Cos-Meta-Md5` header on every put; on GET it requires exactly that header with length 32. A missing/short/long header means the object was not written by this backend (or was corrupted/rewritten externally).","triggerScenarios":"Object.Get succeeds (200, no SDK error) but rsp.Header.Get(\"X-Cos-Meta-Md5\") returns empty or non-32-char string. Happens when the state object was uploaded by the GCS/S3 console, a different tool, a `coscp` copy without metadata, or a prior Terraform version/bug that omitted the header.","commonSituations":"Migrating state by manually uploading `terraform.tfstate` to COS without setting the custom metadata; a third-party sync tool rewrote the object and stripped user metadata; bucket lifecycle rule transitioned the object in a way that dropped custom headers.","solutions":["Confirm the object was originally created by this COS backend (check for X-Cos-Meta-Md5 in the object's metadata via the COS console/API).","If the object is the genuine state but lacks metadata, re-upload it with the custom header set to the hex MD5 of its bytes, or push the state fresh via `terraform state push`.","If the object is stale/foreign, delete it and let Terraform write the state correctly on the next apply.","Avoid manual uploads to the state key path; always use the backend's own Put path so metadata is preserved."],"exampleFix":"// before: state uploaded manually, missing X-Cos-Meta-Md5\n//   -> getObject fails: checksum  invalid\n// after: push state through terraform so the header is written\n//   terraform state push /path/to/terraform.tfstate\n// (or set the header explicitly when uploading out of band)\n//   x-cos-meta-md5: <lowercase 32-char hex md5 of the file>","handlingStrategy":"validation","validationCode":"// Before relying on a state object, verify it carries the COS backend metadata\nfunc hasBackendMetadata(ctx context.Context, client *cos.Client, key string) error {\n    rsp, err := client.Object.Head(ctx, key, nil)\n    if err != nil || rsp == nil { return err }\n    defer rsp.Body.Close()\n    md5 := rsp.Header.Get(\"X-Cos-Meta-Md5\")\n    if len(md5) != 32 {\n        return fmt.Errorf(\"object %s missing valid X-Cos-Meta-Md5 (got %q); re-upload via terraform state push\", key, md5)\n    }\n    return nil\n}","typeGuard":"func isBackendWrittenObject(headers http.Header) bool {\n    return len(headers.Get(\"X-Cos-Meta-Md5\")) == 32\n}","tryCatchPattern":"// If getObject fails with the checksum-invalid message, route the user to\n// re-push the state instead of retrying blindly:\nif strings.Contains(err.Error(), \"checksum\") && strings.Contains(err.Error(), \"invalid\") {\n    return fmt.Errorf(\"state object lacks backend metadata; run `terraform state push <file>`: %w\", err)\n}","preventionTips":["Never upload state files to COS out of band; always use `terraform state push` or the backend itself.","If copying objects between buckets, preserve custom metadata (use COS copy-with-metadata).","After migrations, run a read-only `terraform state pull` to confirm the backend can read the new object.","Avoid lifecycle rules that rewrite objects in a way that strips custom headers."],"tags":["terraform","cos","tencent-cloud","data-integrity","md5","metadata","remote-state","go"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}