{"record":{"id":"bffe5dbaef8304fa","repo":"docker/cli","slug":"signer-name-s-must-start-with-lowercase-alphanu","errorCode":null,"errorMessage":"signer name \"%s\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character","messagePattern":"signer name \"(.+?)\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/docker-trust/trust/signer_add.go","lineNumber":53,"sourceCode":"\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\toptions.signer = args[0]\n\t\t\toptions.repos = args[1:]\n\t\t\treturn addSigner(cmd.Context(), dockerCLI, options)\n\t\t},\n\t\tDisableFlagsInUseLine: true,\n\t}\n\tflags := cmd.Flags()\n\toptions.keys = opts.NewListOpts(nil)\n\tflags.Var(&options.keys, \"key\", \"Path to the signer's public key file\")\n\treturn cmd\n}\n\nvar validSignerName = lazyregexp.New(`^[a-z0-9][a-z0-9\\_\\-]*$`).MatchString\n\nfunc addSigner(ctx context.Context, dockerCLI command.Cli, options signerAddOptions) error {\n\tsignerName := options.signer\n\tif !validSignerName(signerName) {\n\t\treturn fmt.Errorf(\"signer name \\\"%s\\\" must start with lowercase alphanumeric characters and can include \\\"-\\\" or \\\"_\\\" after the first character\", signerName)\n\t}\n\tif signerName == \"releases\" {\n\t\treturn errors.New(\"releases is a reserved keyword, use a different signer name\")\n\t}\n\n\tif options.keys.Len() == 0 {\n\t\treturn errors.New(\"path to a public key must be provided using the `--key` flag\")\n\t}\n\tsignerPubKeys, err := ingestPublicKeys(options.keys.GetSlice())\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar errRepos []string\n\tfor _, repoName := range options.repos {\n\t\t_, _ = fmt.Fprintf(dockerCLI.Out(), \"Adding signer \\\"%s\\\" to %s...\\n\", signerName, repoName)\n\t\tif err := addSignerToRepo(ctx, dockerCLI, signerName, repoName, signerPubKeys); err != nil {\n\t\t\t_, _ = fmt.Fprintln(dockerCLI.Err(), err.Error()+\"\\n\")\n\t\t\terrRepos = append(errRepos, repoName)","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cmd/docker-trust/trust/signer_add.go#L35-L71","documentation":"Returned by `docker trust signer add` (addSigner) when the signer NAME argument fails the validSignerName regex `^[a-z0-9][a-z0-9\\_\\-]*$`. The name must start with a lowercase letter or digit and may contain lowercase alphanumerics, underscores, or hyphens thereafter. Uppercase, leading underscore/hyphen, or other characters are rejected because the name becomes a TUF delegation role (targets/<name>).","triggerScenarios":"Running `docker trust signer add <NAME> ...` where NAME is e.g. 'Alice', '-dev', '_ci', 'Dev_Team', or contains dots/spaces. Validated before any network call.","commonSituations":"Using a human name or team name with capitals; using a leading hyphen that the shell may also misinterpret; migrating from a system whose identifiers allow a wider character set.","solutions":["Use a lowercase-alphanumeric-first name, e.g. 'alice', 'ci-bot', 'team_a'.","Strip or transform uppercase and leading special characters before passing the name.","Note 'releases' is also reserved (separate check at signer_add.go:55) — choose a different name."],"exampleFix":"// before\n$ docker trust signer add Alice registry.example.com/app --key alice.pub\nError: signer name \"Alice\" must start with lowercase alphanumeric...\n\n// after\n$ docker trust signer add alice registry.example.com/app --key alice.pub","handlingStrategy":"validation","validationCode":"// Mirror the CLI's regex before invoking signer add\nimport \"regexp\"\n\nvar validSignerName = regexp.MustCompile(`^[a-z0-9][a-z0-9\\_\\-]*$`).MatchString\n\nfunc validateSignerName(name string) error {\n    if !validSignerName(name) {\n        return fmt.Errorf(\"invalid signer name %q\", name)\n    }\n    if name == \"releases\" { return errors.New(\"releases is reserved\") }\n    return nil\n}","typeGuard":"func isValidSignerName(name string) bool {\n    matched, _ := regexp.MatchString(`^[a-z0-9][a-z0-9\\_\\-]*$`, name)\n    return matched && name != \"releases\"\n}","tryCatchPattern":null,"preventionTips":["Adopt a naming convention: lowercase, start with a letter/digit.","Validate signer names in CI config linting before they reach the CLI.","Remember 'releases' is reserved even when it matches the regex."],"tags":["docker","trust","validation","naming","regex"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}