opentofu/opentofu · error

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

Error message

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

What it means

The state response carried a Content-MD5 header that is not valid base64, so the client cannot decode it for integrity checking, and it refuses the payload. Per RFC 1864 the header must be the base64 encoding of the raw 16-byte MD5 digest; sending hex text or any non-base64 value triggers this. The offending header value is included in the message.

Source

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

	if _, err := io.Copy(buf, resp.Body); err != nil {
		return nil, fmt.Errorf("Failed to read remote state: %w", 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, nil
	}

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

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

	return payload, nil
}

func (c *httpClient) Put(ctx context.Context, data []byte) error {
	// Copy the target URL
	base := *c.URL

	if c.lockID != "" {

View on GitHub (pinned to 3561785c48)

Solutions

  1. Fix the server: send base64.StdEncoding.EncodeToString(md5.Sum(data)) in Go, or the equivalent in the server's language
  2. Alternatively omit the Content-MD5 response header entirely — the client then computes the MD5 locally
  3. Verify what is actually sent: curl -I "$ADDRESS" and try 'echo <value> | base64 -d' to confirm decodability

Example fix

// state server (Go), before
w.Header().Set("Content-MD5", hex.EncodeToString(md5bytes))

// after
w.Header().Set("Content-MD5", base64.StdEncoding.EncodeToString(md5bytes))
Defensive patterns

Strategy: validation

Validate before calling

# Pre-flight: confirm the server's Content-MD5 decodes as base64
val=$(curl -sI "$ADDRESS" | awk -F': ' 'tolower($1)=="content-md5" {print $2}' | tr -d '\r')
if [ -n "$val" ] && ! echo "$val" | base64 -d >/dev/null 2>&1; then
  echo "Content-MD5 is not valid base64: $val"; exit 1
fi

Prevention

When it happens

Trigger: A hand-rolled state server that hex-encodes the MD5 (32 hex chars) instead of base64-encoding the raw digest; an intermediary rewriting or corrupting the header; wrong padding/charset in a custom header injection.

Common situations: Custom state servers written without an RFC 1864-compliant MD5 helper; debug proxies adding their own Content-MD5; header rewritten by CDN transforms.

Understand the failure class

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/cdf50fce14aa9541. Report an issue: GitHub.