{"record":{"id":"25e324d2807a1ed8","repo":"chenhg5/cc-connect","slug":"global-provider-q-already-exists","errorCode":null,"errorMessage":"global provider %q already exists","messagePattern":"global provider %q already exists","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":1473,"sourceCode":"\tdefer configMu.Unlock()\n\tcfg, err := loadLocked()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn cfg.Providers, nil\n}\n\n// AddGlobalProvider appends a provider to the top-level [[providers]] and saves.\nfunc AddGlobalProvider(provider ProviderConfig) error {\n\tconfigMu.Lock()\n\tdefer configMu.Unlock()\n\tcfg, err := loadLocked()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, existing := range cfg.Providers {\n\t\tif existing.Name == provider.Name {\n\t\t\treturn fmt.Errorf(\"global provider %q already exists\", provider.Name)\n\t\t}\n\t}\n\tcfg.Providers = append(cfg.Providers, provider)\n\treturn saveConfig(cfg)\n}\n\n// UpdateGlobalProvider replaces an existing global provider by name.\nfunc UpdateGlobalProvider(name string, provider ProviderConfig) error {\n\tconfigMu.Lock()\n\tdefer configMu.Unlock()\n\tcfg, err := loadLocked()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i := range cfg.Providers {\n\t\tif cfg.Providers[i].Name == name {\n\t\t\tprovider.Name = name // name is immutable in update\n\t\t\tcfg.Providers[i] = provider","sourceCodeStart":1455,"sourceCodeEnd":1491,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/config/config.go#L1455-L1491","documentation":"The global-provider add path (loadLocked + append to cfg.Providers) rejects a provider whose name already exists in the top-level [[providers]] list, returning 'global provider %q already exists'. Global provider names are unique keys across the whole config.","triggerScenarios":"Calling the add-global-provider function when cfg.Providers already contains an entry with existing.Name == provider.Name — re-running setup, retry after an earlier successful add, or two workers adding the same default provider concurrently (the mutex prevents races, not repeats).","commonSituations":"Bootstrap script adding a default global provider on every run; user re-invoking an 'add global provider' command; migrating configs where the provider was already copied into the global section.","solutions":["Check existence first (load config, scan cfg.Providers for the name) and update or skip instead of adding","Remove the existing global provider via the corresponding remove API, then re-add with the new settings","Give the new provider a distinct name if both definitions are genuinely needed"],"exampleFix":"// before\nif err := config.AddGlobalProvider(provider); err != nil { return err }\n// after (idempotent)\nif err := config.AddGlobalProvider(provider); err != nil {\n    if strings.Contains(err.Error(), \"already exists\") { return nil }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"cfg, _ := config.Load()\nfor _, ex := range cfg.Providers {\n    if ex.Name == provider.Name { return nil } // already registered\n}","typeGuard":null,"tryCatchPattern":"if err := config.AddGlobalProvider(provider); err != nil {\n    if strings.Contains(err.Error(), \"already exists\") {\n        return nil // idempotent bootstrap\n    }\n    return err\n}","preventionTips":["Gate global-provider bootstrap on a 'already initialized' marker rather than re-adding","Use upsert semantics where the API allows update-on-existing","Serialize bootstrap steps so two workers cannot both attempt the same add"],"tags":["go","config","duplicate","validation"],"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-14T05:17:10.506Z"}