{"record":{"id":"d71a45fd307ee2e4","repo":"gastownhall/beads","slug":"edge-d-from-key-q-not-found-in-plan","errorCode":null,"errorMessage":"edge %d: from key %q not found in plan","messagePattern":"edge (.+?): from key %q not found in plan","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/graph_apply.go","lineNumber":594,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"node %q: parent key %q not found in plan\", node.Key, parentKey)\n\t\t\t}\n\t\t}\n\t\tfor j, dep := range node.Deps {\n\t\t\tif dep.Target == \"\" {\n\t\t\t\treturn fmt.Errorf(\"node %q: dep %d has empty target\", node.Key, j)\n\t\t\t}\n\t\t\tif dep.Type != \"\" {\n\t\t\t\tdt := types.DependencyType(dep.Type)\n\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 {","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/graph_apply.go#L576-L612","documentation":"Plan edges may specify their source via from_key or from_id. If from_key is set, it must match a node key in the plan; otherwise the edge's source cannot be resolved and validation fails with the edge index.","triggerScenarios":"`bd graph apply` with plan.edges[i].from_key naming a key absent from plan.nodes.","commonSituations":"Typos in from_key; the source node was removed from the plan but its edges remained; edges carried over from a different plan with different keys.","solutions":["Correct from_key to an existing node key in the plan","Add the missing source node to plan.nodes","Remove the stale edge, or use from_id referencing a real issue id"],"exampleFix":"// before\n{\"edges\": [{\"from_key\": \"buld\", \"to_key\": \"deploy\"}]}\n// after\n{\"edges\": [{\"from_key\": \"build\", \"to_key\": \"deploy\"}]}","handlingStrategy":"validation","validationCode":"keys := map[string]bool{}\nfor _, n := range plan.Nodes { keys[n.Key] = true }\nfor i, e := range plan.Edges {\n\tif e.FromKey != \"\" && !keys[e.FromKey] { return fmt.Errorf(\"edge %d: unknown from_key %s\", i, e.FromKey) }\n}","typeGuard":null,"tryCatchPattern":"if err := bd.GraphApply(ctx, plan, opts); err != nil {\n\tif strings.Contains(err.Error(), \"from key\") && strings.Contains(err.Error(), \"not found in plan\") {\n\t\t// fix edge source and retry\n\t}\n}","preventionTips":["Build edges from node objects (passing keys) instead of typing keys by hand","Regenerate edges whenever node keys change","Validate all edge endpoints against plan keys before applying"],"tags":["validation","graph-apply","dangling-reference"],"backgroundTag":"unknown-reference-key","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}