{"record":{"id":"c8de349c325022c8","repo":"gastownhall/beads","slug":"applygraph-edge-d-references-undefined-from-key","errorCode":null,"errorMessage":"applyGraph: edge %d references undefined from_key %q","messagePattern":"applyGraph: edge (.+?) references undefined from_key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1179,"sourceCode":"\t// Build the (childID, parentID) pair set and validate that any planned\n\t// parent-child link does not close a cycle through planned edges or\n\t// already-existing dependencies in the store. This must run before any\n\t// dep inserts to catch the violation before we've written anything.\n\tparentDepPairs := graphParentDepPairs(plan.Nodes, keyToID)\n\tnewSchedulingEdges := make([][2]string, 0, len(plan.Nodes)+len(plan.Edges))\n\tif err := u.validatePlannedBlockingPaths(ctx, plan, keyToID, parentDepPairs); err != nil {\n\t\treturn GraphApplyResult{}, err\n\t}\n\tif err := u.validatePlannedBlockingCycles(ctx, plan, keyToID); err != nil {\n\t\treturn GraphApplyResult{}, err\n\t}\n\t// Preserve failure-before-write for explicit edges that conflict directly\n\t// with an implicit node parent relationship. Parent-first mutation below is\n\t// for transitive hierarchy visibility, not for deferring structural errors.\n\tfor i, edge := range plan.Edges {\n\t\tfromID := resolveEdgeRef(edge.FromKey, edge.FromID, keyToID)\n\t\tif fromID == \"\" {\n\t\t\treturn GraphApplyResult{}, fmt.Errorf(\"applyGraph: edge %d references undefined from_key %q\", i, edge.FromKey)\n\t\t}\n\t\ttoID := resolveEdgeRef(edge.ToKey, edge.ToID, keyToID)\n\t\tif toID == \"\" {\n\t\t\treturn GraphApplyResult{}, fmt.Errorf(\"applyGraph: edge %d references undefined to_key %q\", i, edge.ToKey)\n\t\t}\n\t\tdepType := edge.Type\n\t\tif depType == \"\" {\n\t\t\tdepType = types.DepBlocks\n\t\t}\n\t\tif parentDepPairs[depPairKey(fromID, toID)] && depType != types.DepParentChild {\n\t\t\treturn GraphApplyResult{}, fmt.Errorf(\"applyGraph: edge %d %s->%s duplicates a parent-child relationship with dependency type %q\", i, fromID, toID, depType)\n\t\t}\n\t\tif parentDepPairs[depPairKey(toID, fromID)] && cycleRelevantDepType(depType) {\n\t\t\treturn GraphApplyResult{}, fmt.Errorf(\"applyGraph: edge %d %s->%s creates a blocking reverse of a parent-child relationship\", i, fromID, toID)\n\t\t}\n\t}\n\n\t// Pass 3 — insert node parent-child deps now that all IDs are known. These","sourceCodeStart":1161,"sourceCodeEnd":1197,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1161-L1197","documentation":"applyGraph() validates every edge in an incoming graph plan before writing anything: it resolves each edge's FromKey (or FromID) against the set of issue IDs known to this transaction (keyToID). If the from-side key does not resolve to an existing or same-plan issue, the whole apply is aborted with this error so no partial graph is persisted.","triggerScenarios":"Calling applyGraph with a plan whose Edges[i].FromKey names an issue that is not in the database and not created by an earlier node in the same plan, and where no FromID fallback is set.","commonSituations":"Client built the plan against a different database/worktree; issue key typo'd or stale after deletion; edge references an issue from another repo that was never synced; plan JSON was hand-edited.","solutions":["Ensure the from-issue is created in the same plan (add a node) or already exists via bd list/show before applying","Verify the issue key spelling (bd show <key> must succeed first)","Set edge.FromID explicitly if you have the UUID and the key is unreliable","Sync/pull so remote issues referenced by the plan exist locally"],"exampleFix":"// before\nplan.Edges = append(plan.Edges, GraphEdge{FromKey: \"bd-999\", ToKey: \"bd-1\"}) // bd-999 doesn't exist\n// after\nif _, err := s.GetIssue(ctx, \"bd-999\"); err != nil {\n    plan.Nodes = append(plan.Nodes, GraphNode{Key: \"bd-999\"}) // include it in the plan\n}\nplan.Edges = append(plan.Edges, GraphEdge{FromKey: \"bd-999\", ToKey: \"bd-1\"})","handlingStrategy":"validation","validationCode":"for _, e := range plan.Edges {\n    if _, ok := keyToID[e.FromKey]; !ok && e.FromID == \"\" {\n        return fmt.Errorf(\"edge from_key %q has no node and no FromID\", e.FromKey)\n    }\n}","typeGuard":"func edgeFromResolved(e GraphEdge, keyToID map[string]string) bool {\n    _, byKey := keyToID[e.FromKey]\n    return byKey || e.FromID != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always include a node for every edge endpoint in the plan","Run bd show <key> before referencing an issue","Prefer FromID when keys may be stale","Sync before applying plans produced on another machine"],"tags":["graph-apply","validation","storage"],"backgroundTag":"undefined-issue-reference","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}