{"record":{"id":"57c5be3aee7e3e98","repo":"hashicorp/terraform","slug":"failed-to-store-state-md5-s","errorCode":null,"errorMessage":"failed to store state MD5: %s","messagePattern":"failed to store state MD5: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oss/client.go","lineNumber":129,"sourceCode":"\t\toptions = append(options, oss.ACL(oss.ACLType(c.acl)))\n\t}\n\toptions = append(options, oss.ContentType(\"application/json\"))\n\tif c.serverSideEncryption {\n\t\toptions = append(options, oss.ServerSideEncryption(\"AES256\"))\n\t}\n\toptions = append(options, oss.ContentLength(int64(len(data))))\n\n\tif body != nil {\n\t\tif err := bucket.PutObject(c.stateFile, body, options...); err != nil {\n\t\t\treturn diags.Append(fmt.Errorf(\"failed to upload state %s: %#v\", c.stateFile, err))\n\t\t}\n\t}\n\n\tsum := md5.Sum(data)\n\tif err := c.putMD5(sum[:]); err != nil {\n\t\t// if this errors out, we unfortunately have to error out altogether,\n\t\t// since the next Get will inevitably fail.\n\t\treturn diags.Append(fmt.Errorf(\"failed to store state MD5: %s\", err))\n\t}\n\treturn diags\n}\n\nfunc (c *RemoteClient) Delete() tfdiags.Diagnostics {\n\tvar diags tfdiags.Diagnostics\n\tbucket, err := c.ossClient.Bucket(c.bucketName)\n\tif err != nil {\n\t\treturn diags.Append(fmt.Errorf(\"error getting bucket %s: %#v\", c.bucketName, err))\n\t}\n\n\tlog.Printf(\"[DEBUG] Deleting remote state from OSS: %#v\", c.stateFile)\n\n\tif err := bucket.DeleteObject(c.stateFile); err != nil {\n\t\treturn diags.Append(fmt.Errorf(\"error deleting state %s: %#v\", c.stateFile, err))\n\t}\n\n\tif err := c.deleteMD5(); err != nil {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/oss/client.go#L111-L147","documentation":"In RemoteClient.Put() (client.go:126-129), putMD5 failed. putMD5 writes the state's MD5 digest into TableStore so future Get() calls can detect staleness. The comment at line 127-128 explains the hard fail: with OSS updated but OTS digest stale, the next Get will inevitably mismatch (error 348), so Put aborts rather than ship an inconsistent state.","triggerScenarios":"putMD5()'s otsClient.PutRow (client.go:286) returns a non-nil error (note putMD5 currently swallows the error via log at line 291, but the wrapping at line 129 reflects the original). Triggered by OTS outage, throttling, missing tablestore:PutRow permission, or table deleted between init and apply.","commonSituations":"OTS instance throttled during a burst of applies; RAM policy revoked PutRow mid-session; OTS table dropped; region-wide OTS degradation.","solutions":["Confirm the OTS table still exists and credentials have tablestore:PutRow.","Raise OTS reserved throughput or switch to on-demand capacity if throttling.","Re-run apply once OTS recovers; if the OSS object was written but digest missing, manually write the Digest row to match (per error 348 guidance).","If locking/digest is not needed, drop ots_endpoint/tablestore_table so putMD5 is a no-op (returns nil at line 256)."],"exampleFix":"// before: OTS required but throttled\nbackend \"oss\" {\n  bucket = \"tf-state\"\n  ots_endpoint = \"https://...ots.aliyuncs.com\"\n  tablestore_table = \"terraform_lock\"\n}\n\n// after: drop OTS (no locking/digest) to unblock\nbackend \"oss\" {\n  bucket = \"tf-state\"\n}","handlingStrategy":"retry","validationCode":"// Probe OTS PutRow capability with a throwaway conditional write before the real apply.\nfunc otsWritable(c *tablestore.TableStoreClient, table string) error {\n    // attempt + immediate delete on a synthetic key\n    return nil // implement a round-trip probe if OTS flakiness is common in your env\n}","typeGuard":null,"tryCatchPattern":"// Retry on OTS throttling; if persistent, drop OTS config (no-op putMD5) or repair digest.\nif strings.Contains(err.Error(), \"failed to store state MD5\") {\n    backoffRetry()\n}","preventionTips":["Provision adequate OTS throughput for concurrent applies.","Grant tablestore:PutRow and keep the OTS table present.","Do not run terraform apply if OTS is in regional degradation."],"tags":["alibaba-cloud","tablestore","ots","remote-state","consistency","md5","go"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}