docker/cli · error
could not add signer to repo
Error message
could not add signer to repo: %s: %w
What it means
Returned during `docker trust sign` inside initNotaryRepoWithSigners() when a brand-new notary repository is being initialized and addStagedSigner() fails to create the targets/<username> delegation role (AddDelegationRoleAndKeys / AddDelegationPaths / ReleasesRole setup). %s is the signer role name (username), %w is the notary staging error. This is part of first-time repo bootstrap, not an add-signer flow.
Solutions
- Check permissions and integrity of ~/.docker/trust (read/write access for the current user).
- Avoid usernames with characters that break TUF role path construction; use a simple lowercase username.
- Retry after clearing any partial/locked trust metadata for that repo.
- Inspect the wrapped %w for the crypto-service or staging error to pinpoint key vs metadata failure.
Example fix
// before $ docker trust sign registry.example.com/newrepo:v1 Error: could not add signer to repo: alice: ... // after — fix trust keystore permissions then re-initialize $ chmod -R u+rwX ~/.docker/trust $ docker trust sign registry.example.com/newrepo:v1
Defensive patterns
Strategy: validation
Validate before calling
// Before first sign, ensure the trust keystore is writable and the username is role-safe
func preSignBootstrap(repo string) error {
info, err := os.Stat(filepath.Join(homedir.Dir(), ".docker", "trust"))
if err != nil { return err }
if !info.IsDir() { return errors.New("~/.docker/trust is not a directory") }
if os.Geteuid() == 0 { return errors.New("do not sign as root without a trust keystore owner") }
return nil
} Try / catch
// Bootstrap init errors are usually permanent for the session; surface and stop
out, err := exec.CommandContext(ctx, "docker", "trust", "sign", ref).CombinedOutput()
if err != nil && strings.Contains(string(out), "could not add signer to repo") {
return fmt.Errorf("trust bootstrap failed, check ~/.docker/trust perms: %s", out)
} Prevention
- Use a lowercase-alphanumeric username so the derived delegation role is valid.
- Ensure write access to ~/.docker/trust before first sign.
- Don't share the trust keystore across concurrent processes.
When it happens
Trigger: First `docker trust sign` against a repo where ListTargets() returns ErrRepoNotInitialized/ErrRepositoryNotExist, initNotaryRepoWithSigners runs, getOrGenerateNotaryKey succeeds, but addStagedSigner fails — typically due to crypto-service key creation failure or invalid delegation metadata staging.
Common situations: Corrupt or permission-restricted ~/.docker/trust keystore; running as a user without write access to the trust directory; key generation entropy or hardware-backed key issues; username containing characters not valid in a TUF role name.
Related errors
- failed to sign
- could not add signer to repo
- error removing signer from
- error retrieving signers for
- no valid signing keys for delegation roles
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/09716f5171b067b0.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/docker-trust/trust/sign.go:214
func initNotaryRepoWithSigners(notaryRepo notaryclient.Repository, newSigner data.RoleName) error {
rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
if err != nil {
return err
}
rootKeyID := rootKey.ID()
// Initialize the notary repository with a remotely managed snapshot key
if err := notaryRepo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
return err
}
signerKey, err := getOrGenerateNotaryKey(notaryRepo, newSigner)
if err != nil {
return err
}
if err := addStagedSigner(notaryRepo, newSigner, []data.PublicKey{signerKey}); err != nil {
return fmt.Errorf("could not add signer to repo: %s: %w", strings.TrimPrefix(newSigner.String(), "targets/"), err)
}
return notaryRepo.Publish()
}
// generates an ECDSA key without a GUN for the specified role
func getOrGenerateNotaryKey(notaryRepo notaryclient.Repository, role data.RoleName) (data.PublicKey, error) {
// use the signer name in the PEM headers if this is a delegation key
if data.IsDelegation(role) {
role = data.RoleName(notaryRoleToSigner(role))
}
keys := notaryRepo.GetCryptoService().ListKeys(role)
var err error
var key data.PublicKey
// always select the first key by ID
if len(keys) > 0 {
sort.Strings(keys)
keyID := keys[0]View on GitHub (pinned to 4f84911bfe)