{"record":{"id":"14894d897b592aa7","repo":"docker/cli","slug":"could-not-add-signer-to-repo-s-w-14894d","errorCode":null,"errorMessage":"could not add signer to repo: %s: %w","messagePattern":"could not add signer to repo: (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/docker-trust/trust/signer_add.go","lineNumber":109,"sourceCode":"\t}\n\n\tif _, err = notaryRepo.ListTargets(); err != nil {\n\t\tswitch err.(type) {\n\t\tcase client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:\n\t\t\t_, _ = fmt.Fprintf(dockerCLI.Out(), \"Initializing signed repository for %s...\\n\", repoName)\n\t\t\tif err := getOrGenerateRootKeyAndInitRepo(notaryRepo); err != nil {\n\t\t\t\treturn trust.NotaryError(repoName, err)\n\t\t\t}\n\t\t\t_, _ = fmt.Fprintf(dockerCLI.Out(), \"Successfully initialized %q\\n\", repoName)\n\t\tdefault:\n\t\t\treturn trust.NotaryError(repoName, err)\n\t\t}\n\t}\n\n\tnewSignerRoleName := data.RoleName(path.Join(data.CanonicalTargetsRole.String(), signerName))\n\n\tif err := addStagedSigner(notaryRepo, newSignerRoleName, signerPubKeys); err != nil {\n\t\treturn fmt.Errorf(\"could not add signer to repo: %s: %w\", strings.TrimPrefix(newSignerRoleName.String(), \"targets/\"), err)\n\t}\n\n\treturn notaryRepo.Publish()\n}\n\nfunc ingestPublicKeys(pubKeyPaths []string) ([]data.PublicKey, error) {\n\tpubKeys := []data.PublicKey{}\n\tfor _, pubKeyPath := range pubKeyPaths {\n\t\t// Read public key bytes from PEM file, limit to 1 KiB\n\t\tpubKeyFile, err := os.OpenFile(pubKeyPath, os.O_RDONLY, 0o666)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to read public key from file: %w\", err)\n\t\t}\n\t\tdefer pubKeyFile.Close()\n\t\t// limit to\n\t\tl := io.LimitReader(pubKeyFile, 1<<20)\n\t\tpubKeyBytes, err := io.ReadAll(l)\n\t\tif err != nil {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cmd/docker-trust/trust/signer_add.go#L91-L127","documentation":"Returned by addSignerToRepo() in `docker trust signer add` when addStagedSigner() fails to create the targets/<signerName> delegation role with the supplied public key(s) and the targets/releases delegation. %s is the signer name (role prefix stripped), %w is the notary staging error. Mirrors the bootstrap error in sign.go:214 but occurs in the explicit signer-add path on an already-initialized (or just-initialized) repo.","triggerScenarios":"Running `docker trust signer add <name> <repo> --key <file>` where AddDelegationRoleAndKeys or AddDelegationPaths rejects the staging change — e.g. the delegation role already exists with a conflicting key set, or the staged metadata is malformed.","commonSituations":"Re-adding a signer whose role already exists; supplying a public key that does not match the expected PEM/type; partial trust state left over from a failed prior add.","solutions":["Check whether the signer already exists with `docker trust inspect <repo>` and remove it first if you intend to replace its keys.","Ensure the --key file is a valid PEM public key generated for notary (see ingestPublicKeys parsing).","Clear stale staged changes: notary stages changes; a previously failed add may have left pending changes — re-run or use a fresh client.","Read the wrapped %w for the notary delegation error and address it (conflict, invalid key, etc.)."],"exampleFix":"// before\n$ docker trust signer add alice reg.io/app --key alice.pub\nError: could not add signer to repo: alice: ...\n\n// after — remove existing signer then re-add with the new key\n$ docker trust signer remove alice reg.io/app -f\n$ docker trust signer add alice reg.io/app --key alice-new.pub","handlingStrategy":"validation","validationCode":"// Before adding, check the signer role does not already exist (avoid conflict)\nfunc signerExists(repo, name string) (bool, error) {\n    out, err := exec.Command(\"docker\", \"trust\", \"inspect\", repo).CombinedOutput()\n    if err != nil { return false, err }\n    return strings.Contains(string(out), \"\\\"\"+name+\"\\\"\"), nil\n}","typeGuard":null,"tryCatchPattern":"// If add fails on conflict, remove the existing signer then retry once\nif out, err := exec.CommandContext(ctx, \"docker\", \"trust\", \"signer\", \"add\", name, repo, \"--key\", key).CombinedOutput(); err != nil {\n    if strings.Contains(string(out), \"already\") || strings.Contains(string(out), \"conflict\") {\n        _ = exec.CommandContext(ctx, \"docker\", \"trust\", \"signer\", \"remove\", name, repo, \"-f\").Run()\n        // retry add\n    }\n}","preventionTips":["Inspect existing signers before adding to avoid delegation conflicts.","Supply only valid PEM public keys (see ingestPublicKeys).","When replacing a signer's key, remove then re-add rather than re-adding in place."],"tags":["docker","trust","notary","delegation","signing"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}