{"record":{"id":"749304659e9fca14","repo":"gastownhall/beads","slug":"repository-already-configured-s","errorCode":null,"errorMessage":"repository already configured: %s","messagePattern":"repository already configured: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/config/repos.go","lineNumber":214,"sourceCode":"}\n\n// AddRepo adds a repository to the repos.additional list in config.yaml\n// If primary is not set, it defaults to \".\"\nfunc AddRepo(configPath, repoPath string) error {\n\trepos, err := GetReposFromYAML(configPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get repos config: %w\", err)\n\t}\n\n\t// Set primary to \".\" if not already set (standard multi-repo convention)\n\tif repos.Primary == \"\" {\n\t\trepos.Primary = \".\"\n\t}\n\n\t// Check if repo already exists\n\tfor _, existing := range repos.Additional {\n\t\tif existing == repoPath {\n\t\t\treturn fmt.Errorf(\"repository already configured: %s\", repoPath)\n\t\t}\n\t}\n\n\t// Add the new repo\n\trepos.Additional = append(repos.Additional, repoPath)\n\n\treturn SetReposInYAML(configPath, repos)\n}\n\n// RemoveRepo removes a repository from the repos.additional list in config.yaml\nfunc RemoveRepo(configPath, repoPath string) error {\n\trepos, err := GetReposFromYAML(configPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get repos config: %w\", err)\n\t}\n\n\t// Find and remove the repo\n\tfound := false","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/repos.go#L196-L232","documentation":"AddRepo rejects adding a repository path that is already present in repos.additional in config.yaml. The error message includes the duplicate path. This is an intentional idempotency guard, not a failure of the file operation.","triggerScenarios":"AddRepo(configPath, repoPath) is called and the exact string repoPath already exists in the repos.additional list (exact string comparison, no path normalization).","commonSituations":"Running `bd repo add` twice for the same directory; adding a repo whose path string matches an existing entry (e.g. same path with different casing or trailing slash counts as different — but identical strings collide).","solutions":["Check the existing list first: `bd repo list` or read config.yaml before adding","Skip the call if the repo is already present, or treat this error as success (idempotent add)","Use the exact same path string to detect duplicates yourself before calling","Remove the duplicate entry manually if the list got into a bad state"],"exampleFix":"// before\nrepos, _ := GetReposFromYAML(cfg)\nif !slices.Contains(repos.Additional, p) {\n    AddRepo(cfg, p)\n}\n// after — or simply treat as idempotent\nif err := AddRepo(cfg, p); err != nil && !strings.Contains(err.Error(), \"already configured\") {\n    return err\n}","handlingStrategy":"validation","validationCode":"repos, err := GetReposFromYAML(configPath)\nif err == nil && slices.Contains(repos.Additional, repoPath) {\n    return nil // already added; skip\n}","typeGuard":null,"tryCatchPattern":"if err := AddRepo(cfgPath, repoPath); err != nil {\n    if strings.Contains(err.Error(), \"already configured\") {\n        return nil // treat as idempotent success\n    }\n    return err\n}","preventionTips":["Read the current repos list before adding","Normalize the repo path (filepath.Abs/Clean) so the same directory always produces the same string","Design callers to be idempotent for add operations","Surface `bd repo list` to users before scripted adds"],"tags":["duplicate","config","validation"],"backgroundTag":"repository-already-configured","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}