{"record":{"id":"1cc86d994334b7c2","repo":"docker/cli","slug":"error-could-not-find-signing-keys-for-remote-repo","errorCode":null,"errorMessage":"error: could not find signing keys for remote repository %s, or could not decrypt signing key: %v","messagePattern":"error: could not find signing keys for remote repository (.+?), or could not decrypt signing key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/docker-trust/internal/trust/trust.go","lineNumber":248,"sourceCode":"\n// NotaryError formats an error message received from the notary service\nfunc NotaryError(repoName string, err error) error {\n\tswitch err.(type) {\n\tcase *json.SyntaxError:\n\t\tlogrus.Debugf(\"Notary syntax error: %s\", err)\n\t\treturn fmt.Errorf(\"error: no trust data available for remote repository %s. Try running notary server and setting DOCKER_CONTENT_TRUST_SERVER to its HTTPS address\", repoName)\n\tcase signed.ErrExpired:\n\t\treturn fmt.Errorf(\"error: remote repository %s out-of-date: %v\", repoName, err)\n\tcase trustmanager.ErrKeyNotFound:\n\t\treturn fmt.Errorf(\"error: signing keys for remote repository %s not found: %v\", repoName, err)\n\tcase storage.NetworkError:\n\t\treturn fmt.Errorf(\"error: error contacting notary server: %v\", err)\n\tcase storage.ErrMetaNotFound:\n\t\treturn fmt.Errorf(\"error: trust data missing for remote repository %s or remote repository not found: %v\", repoName, err)\n\tcase trustpinning.ErrRootRotationFail, trustpinning.ErrValidationFail, signed.ErrInvalidKeyType:\n\t\treturn fmt.Errorf(\"warning: potential malicious behavior - trust data mismatch for remote repository %s: %v\", repoName, err)\n\tcase signed.ErrNoKeys:\n\t\treturn fmt.Errorf(\"error: could not find signing keys for remote repository %s, or could not decrypt signing key: %v\", repoName, err)\n\tcase signed.ErrLowVersion:\n\t\treturn fmt.Errorf(\"warning: potential malicious behavior - trust data version is lower than expected for remote repository %s: %v\", repoName, err)\n\tcase signed.ErrRoleThreshold:\n\t\treturn fmt.Errorf(\"warning: potential malicious behavior - trust data has insufficient signatures for remote repository %s: %v\", repoName, err)\n\tcase client.ErrRepositoryNotExist:\n\t\treturn fmt.Errorf(\"error: remote trust data does not exist for %s: %v\", repoName, err)\n\tcase signed.ErrInsufficientSignatures:\n\t\treturn fmt.Errorf(\"error: could not produce valid signature for %s.  If Yubikey was used, was touch input provided?: %v\", repoName, err)\n\tdefault:\n\t\treturn err\n\t}\n}\n\n// AddToAllSignableRoles attempts to add the image target to all the top level\n// delegation roles we can (based on whether we have the signing key and whether\n// the role's path allows us to).\n//\n// If there are no delegation roles, we add to the targets role.","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cmd/docker-trust/internal/trust/trust.go#L230-L266","documentation":"Returned by NotaryError when the notary client raises signed.ErrNoKeys: the local trust store contains no signing key for the repository role, or the key that is present could not be decrypted with the supplied passphrase. This maps to the ErrNoKeys case in the type switch at trust.go:247-248, so it surfaces during any operation that needs to sign or rotate a role (push, init, signer add). The error wraps the underlying notary error so the exact role/key identifier is visible in %v.","triggerScenarios":"Calling repo.Publish(), repo.AddTarget(), repo.RotateKey(), or repo.Initialize() when (a) the local key store (~/.docker/trust/private) has no key for the required role, or (b) the DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE / ROOT_PASSPHRASE env var is wrong/missing so decryption of the on-disk encrypted key fails. Also triggered on a fresh machine that has never imported the repository's signing key but tries to publish to an already-initialized notary repo.","commonSituations":"Developer switches machines without copying ~/.docker/trust/private; CI runner has a clean home dir and only the image pushed before, so it lacks the targets/snapshot key; passphrase env vars were rotated or mistyped in the pipeline; key was generated on a Yubikey that is now unplugged; Docker Content Trust repository passphrase was forgotten so decryption silently fails.","solutions":["Check that the key exists locally: ls ~/.docker/trust/private and confirm a key file for the GUN/role is present; if missing, import it with 'docker trust key load <key.file>' or recover the root key from backup.","Set the correct passphrase env var: export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=<repo-passphrase> (and DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE for root-role operations) before retrying.","If the key is on a Yubikey, ensure it is plugged in and the yubikey-agent/pcscd service is running, then retry.","If the repository was never initialized from this machine and you do not have the key, re-initialize with a new root key only if you accept losing prior signatures: back up then remove ~/.docker/trust/private for that GUN and run a trusted push to bootstrap new metadata.","Verify the key is not corrupt by loading it explicitly with 'notary key list' or 'docker trust key load' and confirming the role/key ID matches the notary repo."],"exampleFix":"# before: passphrase missing, push fails with ErrNoKeys\nDOCKER_CONTENT_TRUST=1 docker push myrepo/img:tag\n# after: supply passphrase env vars\nexport DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE=$ROOT_PASS\nexport DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=$REPO_PASS\nDOCKER_CONTENT_TRUST=1 docker push myrepo/img:tag","handlingStrategy":"validation","validationCode":"// Before push, ensure a signing key exists for the GUN and the passphrase resolves.\nfunc ensureSigningKeyAvailable(repo client.Repository, passphrase string) error {\n    keys := repo.GetCryptoService().ListKeys(data.CanonicalTargetsRole)\n    if len(keys) == 0 {\n        return fmt.Errorf(\"no targets signing key in local store; import with 'docker trust key load'\")\n    }\n    // Probe decrypt by attempting to list all keys (forces decryption lazily);\n    // for a stricter check, exercise GetKey on each ID.\n    for _, id := range keys {\n        if _, _, err := repo.GetCryptoService().GetSignerKey(data.CanonicalTargetsRole); err != nil {\n            return fmt.Errorf(\"cannot decrypt key %s: %w; verify DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE\", id, err)\n        }\n    }\n    return nil\n}","typeGuard":"// Narrow a notary error to the ErrNoKeys case so callers can react specifically.\nfunc isErrNoKeys(err error) bool {\n    if err == nil {\n        return false\n    }\n    return errors.Is(err, signed.ErrNoKeys)\n}","tryCatchPattern":"if err := repo.Publish(); err != nil {\n    if errors.Is(err, signed.ErrNoKeys) {\n        // surface a guided message: import key / set passphrase\n        return fmt.Errorf(\"signing key missing or undecryptable: %w; set DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE\", err)\n    }\n    return trust.NotaryError(gun, err)\n}","preventionTips":["Store repository/root passphrases in a secrets manager and inject via DOCKER_CONTENT_TRUST_*_PASSPHRASE env vars in CI.","Back up ~/.docker/trust/private alongside your code so new machines/CI runners have the signing key.","Run 'docker trust key list' (or notary key list) in a pre-deploy gate to confirm the targets key is present before pushing.","Document which passphrase encrypts which key to avoid trial-and-error decryption."],"tags":["docker","notary","content-trust","signing-keys","passphrase","encryption"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}