{"record":{"id":"d99b9ed8f3e7fa50","repo":"gastownhall/beads","slug":"commands-q-and-q-both-map-to-doc-page-s-md-ren","errorCode":null,"errorMessage":"commands %q and %q both map to doc page %s.md; rename one","messagePattern":"commands %q and %q both map to doc page (.+?)\\.md; rename one","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/help_all.go","lineNumber":329,"sourceCode":"\tif err := os.MkdirAll(outDir, 0o755); err != nil {\n\t\treturn err\n\t}\n\tif err := removeMarkdownFiles(outDir); err != nil {\n\t\treturn err\n\t}\n\n\tcommands := availableCommandNames(root)\n\tif err := writeMarkdownFile(filepath.Join(outDir, \"index.md\"), genericCLIReferenceIndex(root, commands)); err != nil {\n\t\treturn err\n\t}\n\n\t// commandDocID collapses punctuation, so distinct command names can map\n\t// to the same page file; the later write would silently win.\n\tseen := make(map[string]string, len(commands))\n\tfor _, name := range commands {\n\t\tid := commandDocID(name)\n\t\tif prev, ok := seen[id]; ok {\n\t\t\treturn fmt.Errorf(\"commands %q and %q both map to doc page %s.md; rename one\", prev, name, id)\n\t\t}\n\t\tseen[id] = name\n\n\t\tvar out bytes.Buffer\n\t\tif err := writeSingleCommandDoc(&out, root, name); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpath := filepath.Join(outDir, id+\".md\")\n\t\tif err := writeMarkdownFile(path, out.String()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc genericCLIReferenceIndex(root *cobra.Command, commands []string) string {\n\tvar b strings.Builder","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/help_all.go#L311-L347","documentation":"Returned by writeGenericCLIDocsDir when two distinct command names collapse to the same doc page ID via commandDocID (which strips punctuation). This prevents one page silently overwriting the other.","triggerScenarios":"The commands list passed to writeGenericCLIDocsDir contains two names whose commandDocID values are equal (e.g. 'mol pour' and 'mol-pour' or 'mol.pour' both mapping to 'mol-pour.md'); the second hit of a seen id triggers the error.","commonSituations":"Adding a new alias or renamed command to the docs list without removing the old spelling, punctuation-only differences between command names, or duplicate entries in a generated commands list.","solutions":["Rename one of the commands in the docs list so IDs differ, as the message advises.","Remove the duplicate/alias entry from the commands list if both spellings refer to one command.","If the collision is inherent, change commandDocID's collapsing rules deliberately (with a test)."],"exampleFix":"// before: collision\ncommands := []string{\"mol pour\", \"mol-pour\"}\n// after\ncommands := []string{\"mol pour\"}","handlingStrategy":"validation","validationCode":"ids := map[string]string{}\nfor _, name := range commands {\n\tid := commandDocID(name)\n\tif prev, ok := ids[id]; ok { return fmt.Errorf(\"doc id collision: %s vs %s\", prev, name) }\n\tids[id] = name\n}","typeGuard":null,"tryCatchPattern":"if err := writeGenericCLIDocsDir(...); err != nil {\n\tif strings.Contains(err.Error(), \"both map to doc page\") {\n\t\t// dedupe command list and retry\n\t}\n}","preventionTips":["Keep only one spelling per command in the docs list.","Add a unit test asserting commandDocID uniqueness across all commands.","Review punctuation-sensitive naming when adding command aliases."],"tags":["cli","docs-generation","naming-collision"],"backgroundTag":"doc-id-collision","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}