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

  1. Check permissions and integrity of ~/.docker/trust (read/write access for the current user).
  2. Avoid usernames with characters that break TUF role path construction; use a simple lowercase username.
  3. Retry after clearing any partial/locked trust metadata for that repo.
  4. 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

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


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)