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

  1. 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.
  2. 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.
  3. 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.
  4. 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

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


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/55936ae3b16545a1. Report an issue: GitHub.