gastownhall/beads · error
node %q: planned blocking dependencies create a path from pa
Error message
node %q: planned blocking dependencies create a path from parent %q to child %q
What it means
Returned by validateGraphApplyPlannedParentBlockingPaths when a parent's planned blocking dependencies would create a ready-path from the parent to its own child — i.e. the parent could become blocked by (or transitively dependent on) its child, violating parent-child ordering invariants.
Source
Thrown at cmd/bd/graph_apply.go:1202
adj[fromID] = append(adj[fromID], toID)
}
depCache := make(map[string][]*types.Dependency)
for _, node := range plan.Nodes {
childID := keyToID[node.Key]
parentID := node.ParentID
if parentKey := node.effectiveParentKey(); parentKey != "" {
parentID = keyToID[parentKey]
}
if childID == "" || parentID == "" {
continue
}
hasPath, err := graphApplyHasPath(ctx, tx, adj, depCache, parentID, childID, graphApplyReadyPathDependencyType)
if err != nil {
return err
}
if hasPath {
return fmt.Errorf("node %q: planned blocking dependencies create a path from parent %q to child %q", node.Key, parentID, childID)
}
}
return nil
}
// graphApplyHasPath reports whether fromID can reach toID by following the
// in-memory planned adjacency plus existing store dependencies. followExistingDep
// selects which existing dep types the walk traverses, letting callers mirror
// either the early blocking-only preflight or the broader ready-work graph.
func graphApplyHasPath(ctx context.Context, tx storage.Transaction, adj map[string][]string, depCache map[string][]*types.Dependency, fromID, toID string, followExistingDep func(types.DependencyType) bool) (bool, error) {
seen := make(map[string]bool)
var visit func(string) (bool, error)
visit = func(id string) (bool, error) {
if id == toID {
return true, nil
}
if seen[id] {
return false, nilView on GitHub (pinned to 71377f2769)
Solutions
- Remove or reverse the planned blocking edge that connects the parent's subtree to the child
- Detach or re-parent the child before applying the blocking edges
- Inspect existing deps on parent and child with bd dep list to find the offending link
Example fix
// before: parent P planned to block issue X, but X (transitively) blocks child C of P
{"nodes":[{"key":"bd-parent"}],"edges":[{"from":"bd-parent","to":"bd-x"}]}
// after: block from the child side or remove the parent->X edge
{"edges":[{"from":"bd-x","to":"bd-parent"}]} Defensive patterns
Strategy: validation
Validate before calling
// reject blocking edges that cross parent->child subtrees
for _, e := range plan.Edges {
if isAncestorOrDescendant(tree, e.From, e.To) && blocksReadyPath(e) {
return fmt.Errorf("edge %s->%s crosses parent/child boundary", e.From, e.To)
}
} Prevention
- Never add blocking deps between a parent and issues inside its own subtree
- Re-parent issues before restructuring their dependencies
- Model parent-child ordering via hierarchy, not blocking edges
When it happens
Trigger: bd graph apply where node N has parent P, and the planned blocking edges among N/P create a directed path from P to child C along ready-path-relevant dependency types.
Common situations: Adding a blocking dep from a parent to an issue that (transitively) blocks back into the parent's subtree; restructuring hierarchies while stale blocking edges exist between parent and child subtrees.
Related errors
- edge %d %s->%s creates a blocking dependency cycle
- applyGraph: node %q: planned blocking dependencies create a
- db: DependencySQLRepository.ValidateBlockingHierarchy: dep m
- graph dependency cycle would be created: %s
- edge %d %s->%s: checking planned blocking cycle: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4e6c8970fb76c1a7.
Report an issue: GitHub.