docker/cli · error
provided file is not a supported private key - to add a…
Error message
provided file %s is not a supported private key - to add a signer's public key use docker trust signer add
What it means
In loadPrivKeyBytesToStore (key_load.go:94-97), tufutils.ExtractPrivateKeyAttributes could not parse the bytes as a supported private key PEM (it failed to extract role/attributes). The loader concludes the file is not a supported private key and suggests using 'docker trust signer add' for public keys. This is the first check in the import pipeline.
Solutions
- Confirm the file is a private key PEM: head -1 <file> should show '-----BEGIN EC PRIVATE KEY-----' or '-----BEGIN RSA PRIVATE KEY-----' / '-----BEGIN PRIVATE KEY-----'.
- If you actually have a public key for a signer, use 'docker trust signer add <name> <key.pub> <image>' instead of 'docker trust key load'.
- Convert the key to a supported PEM private key format (e.g. openssl ec -in ... -out key.pem) and retry.
- Re-export the private key from the original source (notary key export) ensuring it is the private PEM with the role header.
Example fix
# before: passing a public key by mistake docker trust key load mykey.pub # after (option A): load the private key docker trust key load mykey.pem # after (option B): adding a signer's public key docker trust signer add team-a mykey.pub myrepo/img
Defensive patterns
Strategy: type-guard
Validate before calling
// Sniff the PEM block type before loading to give a precise error.
func isPrivateKeyPEM(path string) (bool, error) {
b, err := os.ReadFile(path)
if err != nil {
return false, err
}
block, _ := pem.Decode(b)
if block == nil {
return false, nil
}
switch block.Type {
case "EC PRIVATE KEY", "RSA PRIVATE KEY", "PRIVATE KEY", "ENCRYPTED PRIVATE KEY":
return true, nil
default:
return false, nil
}
} Type guard
// Guard that a file is a private key before invoking load.
func assertPrivateKeyFile(path string) error {
ok, err := isPrivateKeyPEM(path)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("provided file %s is not a supported private key - to add a signer's public key use docker trust signer add", path)
}
return nil
} Try / catch
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)
} Prevention
- Pass the private key PEM to 'docker trust key load' and the public (.pub) to 'docker trust signer add'.
- Confirm head -1 <file> shows a PRIVATE KEY PEM header before loading.
- Re-export keys in notary's supported PEM format if produced by another tool.
When it happens
Trigger: Loading a file that is actually a PUBLIC key PEM ('PUBLIC KEY' block) rather than a private key; a certificate; an SSH public key; a random text/JSON file; a private key in an unsupported format (e.g. SSH private key, raw DER without PEM envelope, OpenSSH new format); a corrupt or truncated PEM.
Common situations: User confused public and private key files and passes the .pub; exported a key in a format notary does not consume (PKCS#8 vs the expected notary/TUF key PEM with role header); downloaded the wrong artifact from a key management system; concatenated/corrupted PEM.
Related errors
- key name " " must start with lowercase alphanumeric…
- public key path does not exist
- public key file already exists
- key name " " must start with lowercase alphanumeric…
- refusing to load key from
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/ec25eef693280181.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/docker-trust/trust/key_load.go:96
}
if fileInfo.Mode()&nonOwnerReadWriteMask != 0 {
return nil, fmt.Errorf("private key file %s must not be readable or writable by others", keyPath)
}
}
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")
}View on GitHub (pinned to 4f84911bfe)