hashicorp/terraform · error
failed to store state MD5: %w
Error message
failed to store state MD5: %w
What it means
Thrown in RemoteClient.put() (s3/client.go:246) when putMD5() returns an error after a successful state upload. Important: putMD5 swallows the DynamoDB PutItem error (it logs a WARN and returns nil), so the ONLY error it actually returns is `errors.New("invalid payload md5")` when the digest length is not md5.Size. Since put() always computes sum := md5.Sum(data) (16 bytes), this branch is effectively an internal invariant guard that should be unreachable in normal operation.
Source
Thrown at internal/backend/remote-state/s3/client.go:246
if c.acl != "" {
input.ACL = s3types.ObjectCannedACL(c.acl)
}
log.Info("Uploading remote state")
uploader := manager.NewUploader(c.s3Client, func(u *manager.Uploader) {
u.ClientOptions = optFns
})
_, err := uploader.Upload(ctx, input)
if err != nil {
return fmt.Errorf("failed to upload state: %w", err)
}
if err := c.putMD5(ctx, sum[:]); err != nil {
// if this errors out, we unfortunately have to error out altogether,
// since the next Get will inevitably fail.
return fmt.Errorf("failed to store state MD5: %w", err)
}
return nil
}
func (c *RemoteClient) Delete() tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
ctx := context.TODO()
log := c.logger(operationClientDelete)
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
log.Info("Deleting remote state")
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String(c.bucketName),
Key: aws.String(c.path),View on GitHub (pinned to c9def3e214)
Solutions
- Treat this as an internal bug — the state object itself was uploaded successfully, only the digest write was rejected.
- Re-run the Terraform write to recompute and store a fresh digest.
- If it persists, inspect the code path computing the MD5 sum to ensure it is md5.Sum (16 bytes).
Defensive patterns
Strategy: validation
Validate before calling
// Assert the digest length before storing (mirrors putMD5's own guard)
// sum := md5.Sum(data)
// if len(sum) != md5.Size { return errors.New("invalid payload md5") } Try / catch
// Since the state upload already succeeded, a digest-write failure is non-fatal in practice
// if err := c.putMD5(ctx, sum[:]); err != nil {
// log.Warn("state stored but digest write failed; next Get may warn about checksum", "err", err)
// } Prevention
- Always compute the digest with md5.Sum (16 bytes) before putMD5.
- Treat the digest row as best-effort; the state object is the source of truth.
- If this error appears in production, suspect a regression in the checksum path.
When it happens
Trigger: Only reachable if the checksum passed to putMD5 is not exactly 16 bytes (md5.Size). In the shipped put() path that cannot happen, so encountering this error indicates a code regression or a caller that bypassed put() to invoke putMD5 with a malformed digest.
Common situations: Not expected in production. Would surface only from a bug modifying the checksum computation, or a fork calling putMD5 directly with a truncated/expanded digest.
Related errors
- invalid md5
- failed to lock s3 state: %s
- failed to clean up file lock after DynamoDB lock error: %v;
- failed to unlock both S3 and DynamoDB: S3 error: %v, DynamoD
- invalid md5
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/9e165bfa15b5c0c0.
Report an issue: GitHub.