getsops/sops · critical

Failed to verify data integrity. expected mac %q, got %q

Error message

Failed to verify data integrity. expected mac %q, got %q

What it means

After decrypting the stored MAC, DataWithFormat compares it with a freshly computed MAC over the cleartext. A mismatch means the encrypted data does not match its metadata — the plaintext was tampered with, partially written, or the file was edited outside sops. sops refuses to return the data because integrity cannot be guaranteed.

Source

Thrown at decrypt/decrypt.go:67

	cipher := aes.NewCipher()
	mac, err := tree.Decrypt(key, cipher)
	if err != nil {
		return nil, err
	}

	// Compute the hash of the cleartext tree and compare it with
	// the one that was stored in the document. If they match,
	// integrity was preserved
	originalMac, err := cipher.Decrypt(
		tree.Metadata.MessageAuthenticationCode,
		key,
		tree.Metadata.LastModified.Format(time.RFC3339),
	)
	if err != nil {
		return nil, fmt.Errorf("Failed to decrypt original mac: %w", err)
	}
	if originalMac != mac {
		return nil, fmt.Errorf("Failed to verify data integrity. expected mac %q, got %q", originalMac, mac)
	}

	return store.EmitPlainFile(tree.Branches)
}

// Data is a helper that takes encrypted data and a format string,
// decrypts the data and returns its cleartext in an []byte.
// The format string can be `json`, `yaml`, `ini`, `dotenv` or `binary`.
// If the format string is empty, binary format is assumed.
func Data(data []byte, format string) (cleartext []byte, err error) {
	formatFmt := FormatFromString(format)
	return DataWithFormat(data, formatFmt)
}

View on GitHub (pinned to 13442bb981)

Solutions

  1. Restore the original encrypted file from its source of truth (git, S3 versioning) and decrypt again
  2. Never edit encrypted sops files by hand — edit plaintext via sops editor mode and re-encrypt
  3. Re-encrypt the known-good plaintext with sops -e to regenerate consistent metadata if the original is lost
  4. Rule out transport mangling: download with checksum verification, keep binary-safe transfers, normalize line endings consistently

Example fix

// before (transforming the encrypted bytes in-flight corrupts MAC)
processed := strings.ReplaceAll(string(encBytes), "\r\n", "\n")
plain, err := decrypt.Data([]byte(processed), "yaml")
// after
plain, err := decrypt.Data(encBytes, "yaml") // pass bytes untouched
Defensive patterns

Strategy: try-catch

Validate before calling

// detect likely mangling before decryption: mixed line endings or unexpected edits
if bytes.Contains(encBytes, []byte("\r\n")) && bytes.Contains(encBytes, []byte("\n")) {
    return errors.New("encrypted input has mixed line endings; likely modified in transit")
}

Try / catch

plain, err := decrypt.DataWithFormat(encBytes, formatFmt)
if err != nil {
    if strings.Contains(err.Error(), "Failed to verify data integrity") {
        return fmt.Errorf("encrypted data does not match its metadata; restore the original file and never edit encrypted files directly: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: originalMac != mac: manual edits to the encrypted file's data branches, truncation by a partial upload/download, differing newline or encoding transformations between encryption and decryption, or decrypting a file whose metadata belongs to a different version.

Common situations: Pipeline stages that strip whitespace or convert line endings (CRLF/LF) before sops runs; git merge of an encrypted file without re-encrypting; checksum-mismatched S3 download; concatenating sops files or copy-pasting encrypted content through editors.

Related errors


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/db6ea9d90cd00317. Report an issue: GitHub.