{"record":{"id":"a29653b2dea077e1","repo":"gastownhall/beads","slug":"duplicate-explicit-id-q-node-q","errorCode":null,"errorMessage":"duplicate explicit id %q (node %q)","messagePattern":"duplicate explicit id %q \\(node %q\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/graph_apply.go","lineNumber":547,"sourceCode":"\tseenKeys := make(map[string]bool, len(plan.Nodes))\n\tseenIDs := make(map[string]bool)\n\tfor i, node := range plan.Nodes {\n\t\tif node.Key == \"\" {\n\t\t\treturn fmt.Errorf(\"node %d has empty key\", i)\n\t\t}\n\t\tif seenKeys[node.Key] {\n\t\t\treturn fmt.Errorf(\"duplicate node key %q\", node.Key)\n\t\t}\n\t\tseenKeys[node.Key] = true\n\t\tif node.Title == \"\" {\n\t\t\treturn fmt.Errorf(\"node %q has empty title\", node.Key)\n\t\t}\n\t\tif err := validateGraphApplyNodeFields(node, customTypes, customStatuses, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif node.ID != \"\" {\n\t\t\tif seenIDs[node.ID] {\n\t\t\t\treturn fmt.Errorf(\"duplicate explicit id %q (node %q)\", node.ID, node.Key)\n\t\t\t}\n\t\t\tseenIDs[node.ID] = true\n\t\t}\n\t\t// Validate MetadataRefs point to known keys.\n\t\tfor metaKey, refKey := range node.MetadataRefs {\n\t\t\tif !seenKeys[refKey] {\n\t\t\t\tfound := false\n\t\t\t\tfor _, other := range plan.Nodes {\n\t\t\t\t\tif other.Key == refKey {\n\t\t\t\t\t\tfound = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif !found {\n\t\t\t\t\treturn fmt.Errorf(\"node %q: metadata ref %q references unknown key %q\", node.Key, metaKey, refKey)\n\t\t\t\t}\n\t\t\t}\n\t\t}","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/graph_apply.go#L529-L565","documentation":"Nodes may carry an optional explicit `id`. Validation tracks explicit IDs in a set and rejects a plan when two nodes specify the same ID, since duplicate IDs would collide when creating/patching issues. The error names both the duplicate ID and the offending node key.","triggerScenarios":"`bd graph apply` with a plan where two nodes set the same non-empty `id` field.","commonSituations":"Copy-pasting a node block including its explicit id; importing an existing plan and duplicating entries; ids copied from a previous plan without adjusting for re-use.","solutions":["Give one of the nodes a distinct explicit id","Remove the explicit id from the new node so the system assigns one automatically","Ensure generated plans derive ids deterministically and uniquely (e.g. by key)"],"exampleFix":"// before\n{\"key\": \"a\", \"id\": \"bd-100\"}, {\"key\": \"b\", \"id\": \"bd-100\"}\n// after\n{\"key\": \"a\", \"id\": \"bd-100\"}, {\"key\": \"b\"}","handlingStrategy":"validation","validationCode":"ids := map[string]bool{}\nfor _, n := range plan.Nodes {\n\tif n.ID != \"\" {\n\t\tif ids[n.ID] { return fmt.Errorf(\"duplicate explicit id %q\", n.ID) }\n\t\tids[n.ID] = true\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := bd.GraphApply(ctx, plan, opts); err != nil {\n\tif strings.Contains(err.Error(), \"duplicate explicit id\") {\n\t\t// strip or rename ids and retry\n\t}\n}","preventionTips":["Omit explicit ids unless you truly need them","Let the system assign ids for new nodes","When duplicating nodes, always drop the id field"],"tags":["validation","graph-apply","duplicate-id"],"backgroundTag":"duplicate-key-in-plan","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}