{"record":{"id":"6fc0b7129267f1d9","repo":"gastownhall/beads","slug":"edge-d-must-specify-to-key-or-to-id","errorCode":null,"errorMessage":"edge %d: must specify to_key or to_id","messagePattern":"edge (.+?): must specify to_key or to_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/graph_apply.go","lineNumber":603,"sourceCode":"\t\t\t\tif !dt.IsValid() {\n\t\t\t\t\treturn fmt.Errorf(\"node %q: dep %d: invalid dependency type %q\", node.Key, j, dep.Type)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor i, edge := range plan.Edges {\n\t\tif edge.FromKey != \"\" && !seenKeys[edge.FromKey] {\n\t\t\treturn fmt.Errorf(\"edge %d: from key %q not found in plan\", i, edge.FromKey)\n\t\t}\n\t\tif edge.ToKey != \"\" && !seenKeys[edge.ToKey] {\n\t\t\treturn fmt.Errorf(\"edge %d: to key %q not found in plan\", i, edge.ToKey)\n\t\t}\n\t\tif edge.FromKey == \"\" && edge.FromID == \"\" {\n\t\t\treturn fmt.Errorf(\"edge %d: must specify from_key or from_id\", i)\n\t\t}\n\t\tif edge.ToKey == \"\" && edge.ToID == \"\" {\n\t\t\treturn fmt.Errorf(\"edge %d: must specify to_key or to_id\", i)\n\t\t}\n\t\tif edge.Type != \"\" {\n\t\t\tdt := types.DependencyType(edge.Type)\n\t\t\tif !dt.IsValid() {\n\t\t\t\treturn fmt.Errorf(\"edge %d: invalid dependency type %q\", i, edge.Type)\n\t\t\t}\n\t\t}\n\t\tif edge.Gate != \"\" || edge.SpawnerKey != \"\" || edge.SpawnerID != \"\" {\n\t\t\tif graphApplyDependencyType(edge.Type) != types.DepWaitsFor {\n\t\t\t\treturn fmt.Errorf(\"edge %d: gate/spawner fields require type %q\", i, types.DepWaitsFor)\n\t\t\t}\n\t\t\tif edge.Gate != \"\" && !types.IsValidWaitsForGate(edge.Gate) {\n\t\t\t\treturn fmt.Errorf(\"edge %d: invalid gate %q (valid: %s, %s)\", i, edge.Gate, types.WaitsForAllChildren, types.WaitsForAnyChildren)\n\t\t\t}\n\t\t\tif edge.SpawnerKey != \"\" && edge.SpawnerID != \"\" {\n\t\t\t\treturn fmt.Errorf(\"edge %d: cannot specify both spawner_key and spawner_id\", i)\n\t\t\t}\n\t\t\tif edge.SpawnerKey != \"\" && !seenKeys[edge.SpawnerKey] {","sourceCodeStart":585,"sourceCodeEnd":621,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/graph_apply.go#L585-L621","documentation":"During `bd graph apply` plan validation, every edge must identify both endpoints. The 'to' endpoint may be given as a plan key (to_key) or an issue ID (to_id); when both are empty the edge is unresolvable, so validation rejects the plan with this error before any nodes or edges are written.","triggerScenarios":"A graph plan JSON/YAML contains an edge whose ToKey and ToID are both empty strings or omitted; the plan was hand-authored or generated by a tool that did not fill the to endpoint.","commonSituations":"Hand-editing a plan file and deleting the to_key; a generator emitting edges from templates with unfilled placeholders; copy-pasting an edge entry and removing the wrong field.","solutions":["Add a to_key referencing a node key defined in the same plan","Or add a to_id referencing an existing issue ID","Re-generate the plan with the tool that produced it instead of hand-editing"],"exampleFix":"// before\n{\"edges\": [{\"from_key\": \"auth-node\"}]}\n// after\n{\"edges\": [{\"from_key\": \"auth-node\", \"to_key\": \"db-node\"}]}","handlingStrategy":"validation","validationCode":"for i, e := range plan.Edges {\n  if e.ToKey == \"\" && e.ToID == \"\" {\n    return fmt.Errorf(\"edge %d: missing to endpoint (set to_key or to_id)\", i)\n  }\n}","typeGuard":"func hasToEndpoint(e Edge) bool { return e.ToKey != \"\" || e.ToID != \"\" }","tryCatchPattern":null,"preventionTips":["Always emit both from and to endpoints in generated plans","Validate plans with a schema before running bd graph apply","Keep spawner/gate edges on the to endpoint when generating"],"tags":["graph-plan","validation","cli"],"backgroundTag":"graph-plan-edge-missing-endpoint","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}