hashicorp/terraform · error

Failed to decode Content-MD5

Error message

Failed to decode Content-MD5 '%s': %s

What it means

Thrown when the Content-MD5 response header is present but cannot be base64-decoded (client.go:184-191). The backend reads Content-MD5 to set payload.MD5 for integrity verification; if the header is malformed, base64.StdEncoding.DecodeString fails. The two %s fields are the raw header value and the decode error.

Solutions

  1. Inspect the actual Content-MD5 header value the server returns and fix its encoding to base64.
  2. If you control the server, ensure Content-MD5 is base64.StdEncoding of the raw MD5 digest (RFC 2616).
  3. If an intermediary corrupts the header, bypass or reconfigure it.
  4. As a workaround, remove the Content-MD5 header at the server so the client falls back to computing MD5 itself (client.go:193-196).
Defensive patterns

Strategy: try-catch

Try / catch

// If you control a custom client, fall back to computing MD5 locally when the header is malformed:
// payload, diags := httpClient.Get()
// for _, d := range diags {
//   if strings.Contains(d.Description().Summary, "Failed to decode Content-MD5") {
//     // server bug: request operator fix the header encoding
//   }
// }

Prevention

When it happens

Trigger: The state server returns a Content-MD5 header that is not valid base64 (wrong encoding, padding stripped, hex instead of base64, or corrupted). This is a server/intermediary bug, not a client config issue.

Common situations: A custom state server emits a hex-encoded or double-encoded MD5; a CDN/proxy rewrites or corrupts the header; the server mistakenly returns the raw 16-byte digest instead of base64.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/8672be54f9c41042. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/http/client.go:191

	if _, err := io.Copy(buf, resp.Body); err != nil {
		return nil, diags.Append(fmt.Errorf("Failed to read remote state: %s", err))
	}

	// Create the payload
	payload := &remote.Payload{
		Data: buf.Bytes(),
	}

	// If there was no data, then return nil
	if len(payload.Data) == 0 {
		return nil, diags
	}

	// Check for the MD5
	if raw := resp.Header.Get("Content-MD5"); raw != "" {
		md5, err := base64.StdEncoding.DecodeString(raw)
		if err != nil {
			return nil, diags.Append(fmt.Errorf(
				"Failed to decode Content-MD5 '%s': %s", raw, err))
		}

		payload.MD5 = md5
	} else {
		// Generate the MD5
		hash := md5.Sum(payload.Data)
		payload.MD5 = hash[:]
	}

	return payload, diags
}

func (c *httpClient) Put(data []byte) tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics

	// Copy the target URL
	base := *c.URL

View on GitHub (pinned to d32a084675)