gastownhall/beads · error
applyGraph: node %q: adding dep to %q: %w
Error message
applyGraph: node %q: adding dep to %q: %w
What it means
The same inline node dependency as 3151 was constructed successfully but depRepo.Insert failed when persisting it, wrapped with both the node key and the dependency target. The cause lives in the wrapped error: constraint violation, missing endpoint, or storage failure. This is the persistence-stage counterpart of the construction error at issue.go:1277.
Source
Thrown at internal/storage/domain/issue.go:1283
}
if types.IsSchedulingEdge(depType) {
newSchedulingEdges = append(newSchedulingEdges, [2]string{fromID, toID})
}
}
// Per-node inline deps in stable order for this phase, resolved by the
// same shared builder as the embedded executeGraphApply (cmd/bd/graph_apply.go).
for _, node := range plan.Nodes {
for _, nd := range node.Deps {
dep, err := types.NewGraphNodeDependency(keyToID[node.Key], nd.Type, nd.Target, keyToID)
if err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: %w", node.Key, err)
}
if (dep.Type == types.DepParentChild) != parentPhase {
continue
}
if err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp}); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: adding dep to %q: %w", node.Key, nd.Target, err)
}
if types.IsSchedulingEdge(dep.Type) {
newSchedulingEdges = append(newSchedulingEdges, [2]string{dep.IssueID, dep.DependsOnID})
}
}
}
}
if cyclePath, err := u.depRepo.CycleThroughEdges(ctx, newSchedulingEdges); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: final cycle check: %w", err)
} else if cyclePath != "" {
return GraphApplyResult{}, fmt.Errorf("applyGraph: dependency cycle would be created: %s", cyclePath)
}
// Pass 5 — apply deferred assignees.
for i, assignee := range pendingAssignees {
if assignee == "" {
continue
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error for the storage-level cause.
- Confirm both endpoints of the dep are in the same table (matching UseWispsTable).
- Make the plan idempotent — skip or upsert deps that already exist.
- Re-run apply after fixing any missing/deleted target issues.
Example fix
// before: re-running a plan that already inserted the dep causes duplicate insert bd graph apply plan.yaml # second run fails on same edge // after: remove already-applied deps from the plan or use an idempotent apply bd graph apply plan.yaml --skip-existing-deps
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check for duplicates before apply
seen := map[string]bool{}
for _, n := range plan.Nodes {
for _, d := range n.Deps {
k := n.Key + "->" + d.Target + ":" + d.Type
if seen[k] { return fmt.Errorf("duplicate dep %s", k) }
seen[k] = true
}
} Try / catch
if err := bd.GraphApply(ctx, plan); err != nil {
var insertErr *depInsertError
if errors.As(err, &insertErr) {
log.Printf("dep %s -> %s not inserted: %v", insertErr.Node, insertErr.Target, errors.Unwrap(insertErr))
}
return err
} Prevention
- Deduplicate node deps before applying
- Match UseWispsTable to the actual table of both endpoints
- Check for pre-existing identical deps in the DB
When it happens
Trigger: Inserting a node's dependency after construction fails: endpoint issues not in the expected table (wisp vs regular mismatch), duplicate dependency already present, or a database-level error from depRepo.Insert.
Common situations: Re-applying plans that double-insert deps; applying a plan where dep targets live in the wisps table but UseWispsTable is false (or vice versa); transient Dolt/network errors mid-apply; foreign-key style violations when the target issue was deleted between phases.
Related errors
- loading proto: %w
- add dep: cycle check: %w
- add dep: insert: %w
- remove dep: classify source: %w
- remove dep %s -> %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a0b59dd65606dbce.
Report an issue: GitHub.