{"record":{"id":"40552df033222acf","repo":"chenhg5/cc-connect","slug":"command-q-already-exists","errorCode":null,"errorMessage":"command %q already exists","messagePattern":"command %q already exists","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":1697,"sourceCode":"\n// AddCommand adds a global custom command and persists to config.\nfunc AddCommand(cmd CommandConfig) error {\n\tconfigMu.Lock()\n\tdefer configMu.Unlock()\n\tif ConfigPath == \"\" {\n\t\treturn fmt.Errorf(\"config path not set\")\n\t}\n\tdata, err := os.ReadFile(ConfigPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read config: %w\", err)\n\t}\n\tcfg := &Config{}\n\tif err := toml.Unmarshal(data, cfg); err != nil {\n\t\treturn fmt.Errorf(\"parse config: %w\", err)\n\t}\n\tfor _, c := range cfg.Commands {\n\t\tif c.Name == cmd.Name {\n\t\t\treturn fmt.Errorf(\"command %q already exists\", cmd.Name)\n\t\t}\n\t}\n\tcfg.Commands = append(cfg.Commands, cmd)\n\treturn saveConfig(cfg)\n}\n\n// RemoveCommand removes a global custom command and persists to config.\nfunc RemoveCommand(name string) error {\n\tconfigMu.Lock()\n\tdefer configMu.Unlock()\n\tif ConfigPath == \"\" {\n\t\treturn fmt.Errorf(\"config path not set\")\n\t}\n\tdata, err := os.ReadFile(ConfigPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read config: %w\", err)\n\t}\n\tcfg := &Config{}","sourceCodeStart":1679,"sourceCodeEnd":1715,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/config/config.go#L1679-L1715","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check existing commands first (config listing API or read config.toml) and skip the add if the name exists for idempotency.","Use a different, unique name for the new command.","Remove the existing command with config.RemoveCommand(name) if it should be replaced, then re-add.","Normalize (trim/lowercase) names before comparing to avoid near-duplicate collisions."],"exampleFix":"// before\nconfig.AddCommand(cmd) // errors if name exists\n\n// after\nif err := config.AddCommand(cmd); err != nil {\n    if strings.Contains(err.Error(), \"already exists\") {\n        return nil // idempotent skip\n    }\n    return err\n}","handlingStrategy":"validation","validationCode":"cmds, err := config.ListCommands()\nif err != nil {\n    return err\n}\nfor _, c := range cmds {\n    if c.Name == cmd.Name {\n        return fmt.Errorf(\"command %q exists; choose another name\", cmd.Name)\n    }\n}","typeGuard":null,"tryCatchPattern":"err := config.AddCommand(cmd)\nif err != nil && strings.Contains(err.Error(), \"already exists\") {\n    return nil // treat as idempotent success\n}","preventionTips":["Make install/setup scripts idempotent: skip when the name exists.","Normalize (trim/lowercase) command names before comparing or storing.","Show the existing command to the user when a collision is detected.","Use Remove+Add explicitly when replacement is intended."],"tags":["config","duplicate","go"],"backgroundTag":"file-already-exists","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}