chenhg5/cc-connect · error

command %q already exists

Error message

command %q already exists

What it means

AddCommand rejects the operation because a command with the same name already exists in the global commands list. This is a deliberate duplicate-name guard, not an I/O failure. Pick a different name or remove the existing command first.

Source

Thrown at config/config.go:1697

// AddCommand adds a global custom command and persists to config.
func AddCommand(cmd CommandConfig) error {
	configMu.Lock()
	defer configMu.Unlock()
	if ConfigPath == "" {
		return fmt.Errorf("config path not set")
	}
	data, err := os.ReadFile(ConfigPath)
	if err != nil {
		return fmt.Errorf("read config: %w", err)
	}
	cfg := &Config{}
	if err := toml.Unmarshal(data, cfg); err != nil {
		return fmt.Errorf("parse config: %w", err)
	}
	for _, c := range cfg.Commands {
		if c.Name == cmd.Name {
			return fmt.Errorf("command %q already exists", cmd.Name)
		}
	}
	cfg.Commands = append(cfg.Commands, cmd)
	return saveConfig(cfg)
}

// RemoveCommand removes a global custom command and persists to config.
func RemoveCommand(name string) error {
	configMu.Lock()
	defer configMu.Unlock()
	if ConfigPath == "" {
		return fmt.Errorf("config path not set")
	}
	data, err := os.ReadFile(ConfigPath)
	if err != nil {
		return fmt.Errorf("read config: %w", err)
	}
	cfg := &Config{}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check existing commands first (config listing API or read config.toml) and skip the add if the name exists for idempotency.
  2. Use a different, unique name for the new command.
  3. Remove the existing command with config.RemoveCommand(name) if it should be replaced, then re-add.
  4. Normalize (trim/lowercase) names before comparing to avoid near-duplicate collisions.

Example fix

// before
config.AddCommand(cmd) // errors if name exists

// after
if err := config.AddCommand(cmd); err != nil {
    if strings.Contains(err.Error(), "already exists") {
        return nil // idempotent skip
    }
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

cmds, err := config.ListCommands()
if err != nil {
    return err
}
for _, c := range cmds {
    if c.Name == cmd.Name {
        return fmt.Errorf("command %q exists; choose another name", cmd.Name)
    }
}

Try / catch

err := config.AddCommand(cmd)
if err != nil && strings.Contains(err.Error(), "already exists") {
    return nil // treat as idempotent success
}

Prevention

When it happens

Trigger: Calling config.AddCommand(cmd) where cmd.Name equals the Name field of any entry already in cfg.Commands after parsing the config (config/config.go:1697).

Common situations: Re-running an install/setup script that adds the same custom command twice; idempotency-ignorant tooling; user re-adding a command they forgot exists; case/whitespace variants being auto-trimmed to a colliding name.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/40552df033222acf. Report an issue: GitHub.