gastownhall/beads · error
node %q: adding dep to %q: %w
Error message
node %q: adding dep to %q: %w
What it means
This wraps a storage failure from tx.AddDependency while inserting an inline node dependency (the dep already constructed successfully). The apply transaction is rolled back and the node key plus dependency target are included to help locate the offending relation.
Source
Thrown at cmd/bd/graph_apply.go:1077
}
}
// Add per-node inline dependencies in stable order for this phase.
for i, node := range plan.Nodes {
for _, dep := range node.Deps {
depType := types.DependencyType(dep.Type)
if depType == "" {
depType = types.DepBlocks
}
if (depType == types.DepParentChild) != parentPhase {
continue
}
d, err := types.NewGraphNodeDependency(issues[i].ID, depType, dep.Target, keyToID)
if err != nil {
return fmt.Errorf("node %q: %w", node.Key, err)
}
if err := tx.AddDependency(ctx, d, actor); err != nil {
return fmt.Errorf("node %q: adding dep to %q: %w", node.Key, dep.Target, err)
}
if graphApplySchedulingDependencyType(d.Type) {
newSchedulingEdges = append(newSchedulingEdges, [2]string{d.IssueID, d.DependsOnID})
}
}
}
}
if cyclePath, err := tx.CycleThroughEdges(ctx, newSchedulingEdges); err != nil {
return fmt.Errorf("final graph cycle check: %w", err)
} else if cyclePath != "" {
return fmt.Errorf("graph dependency cycle would be created: %s", cyclePath)
}
// Apply deferred assignees.
for i, assignee := range pendingAssignees {
updates := map[string]interface{}{
"assignee": assignee,
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped underlying error for the specific storage cause
- Confirm the target issue exists right before applying (bd show <target>)
- Avoid concurrent writers to the same database during graph apply
- Deduplicate deps in the plan to prevent duplicate-dependency rejections
Example fix
// before: two agents applying overlapping plans concurrently bd graph apply plan.json & bd graph apply plan.json // after: serialize applies bd graph apply plan.json && bd graph apply plan2.json
Defensive patterns
Strategy: try-catch
Validate before calling
for _, n := range plan.Nodes {
for _, d := range n.Deps {
if !issueExists(keyToID[d.Target]) { return fmt.Errorf("target %s missing", d.Target) }
}
} Type guard
func depsPersistable(n Node, db DB, keyToID map[string]string) bool {
return len(n.Deps) == 0 || every(n.Deps, func(d Dep) bool { return db.HasIssue(keyToID[d.Target]) })
} Try / catch
if err := bd.GraphApply(ctx, plan); err != nil {
if strings.Contains(err.Error(), "adding dep to") {
// apply is atomic; retry once storage is healthy
return retryGraphApply(ctx, plan)
}
return err
} Prevention
- Serialize graph applies; avoid parallel agents writing the same DB
- Re-verify target issues exist immediately before applying
- Retry idempotently — failed applies roll back the whole transaction
When it happens
Trigger: node.Deps entry passes NewGraphNodeDependency but tx.AddDependency(ctx, d, actor) errors — e.g. target issue missing in storage, constraint violation, duplicate dependency, or backend failure mid-transaction.
Common situations: Concurrent deletion of the target issue between validation and insert, re-applying a partially applied plan causing duplicates, or Dolt storage errors.
Related errors
- node %q: adding parent-child dep: %w
- adding edge %s->%s: %w
- final graph cycle check: %w
- node %q: setting assignee: %w
- db: DependencySQLRepository.Insert: dep must not be nil
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2e1c5465b432e9e2.
Report an issue: GitHub.