caddyserver/caddy · critical

command already registered: %s

Error message

command already registered: %s

What it means

RegisterCommand panics when a command Name collides with one already registered. Command names are a flat, global namespace (commands map guarded by commandsMu), so two plugins — or a plugin and a built-in like 'start' — cannot both claim the same name.

Source

Thrown at cmd/commands.go:592

// if the name does not meet the described format, or if
// any of the fields are missing from cmd.
//
// This function should be used in init().
func RegisterCommand(cmd Command) {
	commandsMu.Lock()
	defer commandsMu.Unlock()

	if cmd.Name == "" {
		panic("command name is required")
	}
	if cmd.Func == nil && cmd.CobraFunc == nil {
		panic("command function missing")
	}
	if cmd.Short == "" {
		panic("command short string is required")
	}
	if _, exists := commands[cmd.Name]; exists {
		panic("command already registered: " + cmd.Name)
	}
	if !commandNameRegex.MatchString(cmd.Name) {
		panic("invalid command name")
	}
	defaultFactory.Use(func(rootCmd *cobra.Command) {
		rootCmd.AddCommand(caddyCmdToCobra(cmd))
	})
	commands[cmd.Name] = cmd
}

var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Rename your plugin's command to something unique (vendor-prefix it, e.g. 'acme-verify')
  2. Remove the duplicate plugin from the build
  3. Check existing names with 'caddy help' in a build without your plugin before choosing

Example fix

// before
caddy.RegisterCommand(caddy.Command{Name: "list", ...}) // collides with built-in

// after
caddy.RegisterCommand(caddy.Command{Name: "myplugin-list", ...})
Defensive patterns

Strategy: validation

Validate before calling

var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)
if !commandNameRegex.MatchString(name) {
    return fmt.Errorf("command name %q invalid", name)
}

Prevention

When it happens

Trigger: A plugin registers a command named e.g. "list" or "adapt" that caddy's cmd package (or another loaded plugin) already registered; the second RegisterCommand call panics during init.

Common situations: A custom build with several plugins where two expose the same subcommand; a plugin reusing a built-in name ('reload', 'stop', 'validate'); two versions of the same plugin accidentally linked in.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/b63296731b735248. Report an issue: GitHub.