docker/cli · error
cannot load key from provided file
Error message
cannot load key from provided file %s: %w
What it means
In loadPrivKeyBytesToStore (key_load.go:98-100), the file passed the private-key attribute extraction (so it looks like a private key) but decodePrivKeyIfNecessary failed. decodePrivKeyIfNecessary (key_load.go:105-118) detects encrypted PEM (DEK-Info header or 'ENCRYPTED PRIVATE KEY' type) and, when there is no 'path' header, calls trustmanager.GetPasswdDecryptBytes to decrypt; if that returns an error it returns the hard-coded 'could not decrypt key', which is then wrapped as 'cannot load key from provided file <path>'.
Solutions
- Enter the correct passphrase that was used to encrypt the key file (distinct from the repo passphrase used by the trust store).
- If the key should be unencrypted, re-export it without encryption (openssl ec -in enc.pem -out plain.pem) and load the unencrypted file.
- Remove a conflicting DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE if it is being auto-supplied and is wrong, so you are prompted interactively.
- Verify the PEM is not corrupt (openssl ec -in <file> -noout to test decryption with the known passphrase).
Example fix
# before: wrong passphrase for an encrypted key docker trust key load enc-priv.key # -> cannot load key (could not decrypt) # after (option A): supply correct passphrase interactively # after (option B): decrypt the key first, then load openssl ec -in enc-priv.key -out plain-priv.key docker trust key load plain-priv.key
Defensive patterns
Strategy: validation
Validate before calling
// Probe decryption with a candidate passphrase before importing.
func canDecryptKey(path, passphrase string) error {
b, err := os.ReadFile(path)
if err != nil {
return err
}
block, _ := pem.Decode(b)
if block == nil {
return errors.New("not a PEM file")
}
_, hasDEK := block.Headers["DEK-Info"]
if !hasDEK && block.Type != "ENCRYPTED PRIVATE KEY" {
return nil // unencrypted
}
if _, ok := block.Headers["path"]; ok {
return nil // notary-managed, decryption handled by store
}
// Attempt decrypt with the candidate passphrase.
if _, _, err := trustmanager.GetPasswdDecryptBytes(fixedPassRetriever(passphrase), b, "", "encrypted"); err != nil {
return fmt.Errorf("wrong passphrase or unsupported encryption: %w", err)
}
return nil
} Try / catch
if privKeyBytes, err = decodePrivKeyIfNecessary(privKeyBytes, passRet); err != nil {
return fmt.Errorf("cannot load key from provided file %s: %w", keyPath, err)
} Prevention
- Know the passphrase that originally encrypted the key file (it may differ from the repo passphrase).
- If unsure, decrypt the key with openssl first and load the unencrypted PEM.
- Avoid passing an unrelated DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE that hijacks the interactive prompt.
- Test decryption with 'openssl ec -in <file> -noout' before loading.
When it happens
Trigger: Loading an encrypted private key PEM where the supplied passphrase is wrong, the passphrase retriever errored, or the encryption parameters (DEK-Info/cipher) are unsupported/corrupt. The interactive passphrase prompt was given the wrong value, or DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE does not match the key's encryption passphrase.
Common situations: Wrong passphrase entered at the prompt; env var passphrase mismatch; key was encrypted with a different passphrase than the one configured; copy/paste error in the passphrase; key encrypted with an algorithm the notary crypto layer cannot decrypt.
Related errors
- error: could not find signing keys for remote repository
- error: could not produce valid signature for
- failed to generate key for
- error importing key from
- private key file must not be readable or writable by others
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/f33c744fa57eb4f1.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/docker-trust/trust/key_load.go:99
}
}
from, err := os.OpenFile(keyPath, os.O_RDONLY, notary.PrivExecPerms)
if err != nil {
return nil, err
}
defer from.Close()
return io.ReadAll(from)
}
func loadPrivKeyBytesToStore(privKeyBytes []byte, privKeyImporters []trustmanager.Importer, keyPath, keyName string, passRet notary.PassRetriever) error {
var err error
if _, _, err = tufutils.ExtractPrivateKeyAttributes(privKeyBytes); err != nil {
return fmt.Errorf("provided file %s is not a supported private key - to add a signer's public key use docker trust signer add", keyPath)
}
if privKeyBytes, err = decodePrivKeyIfNecessary(privKeyBytes, passRet); err != nil {
return fmt.Errorf("cannot load key from provided file %s: %w", keyPath, err)
}
// Make a reader, rewind the file pointer
return trustmanager.ImportKeys(bytes.NewReader(privKeyBytes), privKeyImporters, keyName, "", passRet)
}
func decodePrivKeyIfNecessary(privPemBytes []byte, passRet notary.PassRetriever) ([]byte, error) {
pemBlock, _ := pem.Decode(privPemBytes)
_, containsDEKInfo := pemBlock.Headers["DEK-Info"]
if containsDEKInfo || pemBlock.Type == "ENCRYPTED PRIVATE KEY" {
// if we do not have enough information to properly import, try to decrypt the key
if _, ok := pemBlock.Headers["path"]; !ok {
privKey, _, err := trustmanager.GetPasswdDecryptBytes(passRet, privPemBytes, "", "encrypted")
if err != nil {
return []byte{}, errors.New("could not decrypt key")
}
privPemBytes = privKey.Private()
}
}View on GitHub (pinned to 4f84911bfe)