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

  1. Treat this as an internal bug — the state object itself was uploaded successfully, only the digest write was rejected.
  2. Re-run the Terraform write to recompute and store a fresh digest.
  3. 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

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


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