gastownhall/beads · error

node %q: adding parent-child dep: %w

Error message

node %q: adding parent-child dep: %w

What it means

This error wraps a storage-layer failure that occurred while inserting the parent-child dependency for a node during `bd graph apply`. Every node that declares a parent gets a DepParentChild dependency written inside the apply transaction; if tx.AddDependency rejects it (e.g. the referenced parent ID does not exist or the storage layer errors), the whole apply transaction is aborted and the underlying reason is wrapped with the node key for identification.

Source

Thrown at cmd/bd/graph_apply.go:1025

		}

		// Add node parent-child dependencies first. The explicit and inline
		// dependency sources below are also processed parent-first, so every
		// blocking edge sees the plan's full hierarchy in storage.
		for i, node := range plan.Nodes {
			parentKey := node.effectiveParentKey()
			parentID := node.ParentID
			if parentKey != "" {
				parentID = keyToID[parentKey]
			}
			if parentID != "" {
				dep := &types.Dependency{
					IssueID:     issues[i].ID,
					DependsOnID: parentID,
					Type:        types.DepParentChild,
				}
				if err := tx.AddDependency(ctx, dep, actor); err != nil {
					return fmt.Errorf("node %q: adding parent-child dep: %w", node.Key, err)
				}
				newSchedulingEdges = append(newSchedulingEdges, [2]string{dep.IssueID, dep.DependsOnID})
			}
		}

		for phase := 0; phase < 2; phase++ {
			parentPhase := phase == 0
			// Add explicit edges in stable order for this phase.
			for i, edge := range plan.Edges {
				fromID := resolveEdgeRef(edge.FromKey, edge.FromID, keyToID)
				toID := resolveEdgeRef(edge.ToKey, edge.ToID, keyToID)
				depType := graphApplyDependencyType(edge.Type)
				if (depType == types.DepParentChild) != parentPhase {
					continue
				}
				if parentDepPairs[graphApplyDepPairKey(fromID, toID)] {
					if depType == types.DepParentChild {
						continue

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify every node's parent key exists in the plan's nodes section and resolves via keyToID
  2. Check the database still contains the parent issue (bd show <parent-id>) before applying
  3. Re-generate the graph plan from a fresh export so parent references match current IDs
  4. Inspect the wrapped underlying error for storage-specific causes (lock, connectivity)

Example fix

// before: plan references a parent key absent from the plan
{"key":"child","parent":"task-9"} // task-9 not in nodes
// after: ensure the parent node is declared in the same plan
{"key":"task-9",...},{"key":"child","parent":"task-9"}
Defensive patterns

Strategy: validation

Validate before calling

for _, n := range plan.Nodes {
  if n.Parent != "" && !keysInPlanOrDB(n.Parent) {
    return fmt.Errorf("node %q: parent %q not found", n.Key, n.Parent)
  }
}

Type guard

func parentResolves(n Node, keyToID map[string]string) bool {
  return n.Parent == "" || keyToID[n.Parent] != ""
}

Try / catch

if err := bd.GraphApply(ctx, plan); err != nil {
  var npe *NodeParentError
  if errors.As(err, &npe) { /* fix plan parent refs */ }
  return err
}

Prevention

When it happens

Trigger: Applying a graph plan where a node has a non-empty parentKey/ParentID and tx.AddDependency(ctx, dep, actor) returns an error — typically because the parent issue ID is not present in the database, a dependency constraint is violated, or the storage backend failed mid-transaction.

Common situations: Graph JSON files referencing parent keys that don't resolve to created issues, applying a plan against a database where the parent was deleted, or a corrupt/locked Dolt storage connection.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/720380590996af47. Report an issue: GitHub.