getsops/sops · error

failed to decrypt identity file: %v

Error message

failed to decrypt identity file: %v

What it means

While decrypting an encrypted age identity file, any read/decryption error other than the recognized incorrect-passphrase case is wrapped as "failed to decrypt identity file". This covers I/O errors and malformed ciphertext encountered before identities can be parsed. It signals the identity file could not be turned into plaintext at all.

Source

Thrown at age/encrypted_keys.go:73

		return fileKey, nil
	}
	i.NoMatchWarning()
	return nil, age.ErrIncorrectIdentity
}

func (i *EncryptedIdentity) decrypt() error {
	d, err := age.Decrypt(bytes.NewReader(i.Contents), &LazyScryptIdentity{i.Passphrase})
	if e := new(age.NoIdentityMatchError); errors.As(err, &e) {
		// ScryptIdentity returns ErrIncorrectIdentity for an incorrect
		// passphrase, which would lead Decrypt to returning "no identity
		// matched any recipient". That makes sense in the API, where there
		// might be multiple configured ScryptIdentity. Since in cmd/age there
		// can be only one, return a better error message.
		i.IncorrectPassphrase()
		return fmt.Errorf("incorrect passphrase")
	}
	if err != nil {
		return fmt.Errorf("failed to decrypt identity file: %v", err)
	}
	i.identities, err = age.ParseIdentities(d)
	return err
}

// LazyScryptIdentity is an age.Identity that requests a passphrase only if it
// encounters an scrypt stanza. After obtaining a passphrase, it delegates to
// ScryptIdentity.
type LazyScryptIdentity struct {
	Passphrase func() (string, error)
}

var _ age.Identity = &LazyScryptIdentity{}

func (i *LazyScryptIdentity) Unwrap(stanzas []*age.Stanza) (fileKey []byte, err error) {
	for _, s := range stanzas {
		if s.Type == "scrypt" && len(stanzas) != 1 {
			return nil, errors.New("an scrypt recipient must be the only one")

View on GitHub (pinned to 13442bb981)

Solutions

  1. Verify the identity file is intact and is a valid age-encrypted (possibly armored) file.
  2. Re-copy or restore the key file from a backup.
  3. Update age/SOPS if the file was produced by a newer format version.

Example fix

// before
$ head -c 100 key.txt > truncated-key.txt  # corrupted key file
// after
$ age -d -o key.txt key.txt.age            # restore full, valid identity file
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(keyPath)
if err != nil {
    return err
}
if len(data) == 0 || !bytes.HasPrefix(bytes.TrimSpace(data), []byte("-----BEGIN")) && !isAgeFile(data) {
    return fmt.Errorf("%s does not look like an age identity file", keyPath)
}

Try / catch

fileKey, err := identity.Unwrap(stanzas)
if err != nil && strings.Contains(err.Error(), "failed to decrypt identity file") {
    // restore the key file from backup before retrying
}

Prevention

When it happens

Trigger: Calling Unwrap on a LazyScryptIdentity when reading/decrypting the encrypted identity file fails with an unexpected error — corrupted file, truncated download, unsupported armor, or I/O failure.

Common situations: Partially copied or corrupted key files; files encrypted with an incompatible age version; disk/permission errors mid-read.

Related errors


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