hashicorp/terraform · error
failed to open file at %v: checksum %s invalid
Error message
failed to open file at %v: checksum %s invalid
What it means
Raised by getObject() in the Tencent COS remote-state client when the downloaded object's 'X-Cos-Meta-Md5' header is missing or malformed. The client requires this custom metadata to be exactly a 32-character hex MD5 digest; if it is absent or the wrong length the object is treated as unreadable because its integrity cannot be verified. This guard exists because Terraform state is critical infrastructure state, so the backend refuses to trust an object whose provenance checksum was never recorded.
Source
Thrown at internal/backend/remote-state/cos/client.go:204
err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
return
}
defer rsp.Body.Close()
log.Printf("[DEBUG] getObject %s: code: %d, error: %v", cosFile, rsp.StatusCode, err)
if err != nil {
if rsp.StatusCode == 404 {
err = nil
} else {
err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
}
return
}
checksum = rsp.Header.Get("X-Cos-Meta-Md5")
log.Printf("[DEBUG] getObject %s: checksum: %s", cosFile, checksum)
if len(checksum) != 32 {
err = fmt.Errorf("failed to open file at %v: checksum %s invalid", cosFile, checksum)
return
}
exists = true
data, err = ioutil.ReadAll(rsp.Body)
log.Printf("[DEBUG] getObject %s: data length: %d", cosFile, len(data))
if err != nil {
err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
return
}
check := fmt.Sprintf("%x", md5.Sum(data))
log.Printf("[DEBUG] getObject %s: check: %s", cosFile, check)
if check != checksum {
err = fmt.Errorf("failed to open file at %v: checksum mismatch, %s != %s", cosFile, check, checksum)
return
}
View on GitHub (pinned to c9def3e214)
Solutions
- Re-write the state object through Terraform itself (terraform plan/apply with the COS backend) so the 'X-Cos-Meta-Md5' header is set correctly, or run 'terraform state push' against the backend.
- If migrating from another backend, use 'terraform state pull' on the source, then 'terraform state push --force' on the COS target so the new backend writes the object with correct metadata.
- Inspect the object metadata in the Tencent COS console/coscli to confirm the X-Cos-Meta-Md5 header is present and is a 32-char hex string; if a manual upload, re-upload with the header set to the md5 hex of the file.
- Remove the stale object and let Terraform recreate it on the next write if no live state needs preserving.
Example fix
# before: object uploaded without metadata
coscli cp terraform.tfstate cos://my-bucket/terraform/state/default.tfstate
# after: upload preserving/setting the X-Cos-Meta-Md5 header (md5 hex)
MD5=$(md5sum terraform.tfstate | awk '{print $1}')
coscli cp --add-header X-Cos-Meta-Md5:$MD5 terraform.tfstate cos://my-bucket/terraform/state/default.tfstate
# preferred: let terraform write it natively
terraform init && terraform state push --force terraform.tfstate Defensive patterns
Strategy: validation
Validate before calling
// Before relying on a remote object, verify it carries the expected metadata.
// (caller-side preflight, e.g. in a state-migration helper)
func hasCOSMd5Meta(ctx context.Context, c *cos.Client, bucket, key string) (bool, error) {
_, err := c.Object.GetMetaData(ctx, key, nil)
if err != nil { return false, err }
// ensure X-Cos-Meta-Md5 is present and 32 hex chars
h := "" // read from ObjectHead response header X-Cos-Meta-Md5
return len(h) == 32 && isHex(h), nil
} Prevention
- Always write state/lock objects through the COS backend itself so the X-Cos-Meta-Md5 header is set.
- When migrating state, use 'terraform state push' rather than copying objects out-of-band.
- If you must upload manually, compute md5 and set X-Cos-Meta-Md5 to the 32-char hex digest.
When it happens
Trigger: The state/lock object exists in COS but was uploaded by an external tool, a different (older) backend version, or a manual process that did not set the 'X-Cos-Meta-Md5' custom header. Triggered on every Get()/Lock()/lockInfo() call that successfully downloads the object (HTTP 200) but then sees len(checksum) != 32 at client.go:203.
Common situations: State file was hand-uploaded with the Tencent console or coscli without metadata; migrating from another backend and the object was copied without preserving custom headers; a bug in an older terraform-provider-tencentcloud that omitted the header on writes; the object was written by a non-Terraform pipeline.
Related errors
- failed to open file at %v: checksum mismatch, %s != %s
- blob metadata %q was empty
- failed to delete lock info from metadata: %s
- Key %q could not be found
- default state is not allowed to be deleted
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/55936ae3b16545a1.
Report an issue: GitHub.