gastownhall/beads · error
applyGraph: edge %d (%s -> %s): %w
Error message
applyGraph: edge %d (%s -> %s): %w
What it means
applyGraph applies a dependency-graph plan and wraps any failure from inserting an edge (dependency) between two issues with the edge index and its from/to issue IDs. This error means the depRepo.Insert call for one edge failed — the edge was constructed fine, but persisting it into the dependencies table (or wisps table) returned an error. The underlying wrapped error carries the real cause (constraint violation, missing issue, storage failure).
Source
Thrown at internal/storage/domain/issue.go:1264
continue
}
if parentDepPairs[depPairKey(fromID, toID)] {
if depType == types.DepParentChild {
continue
}
return GraphApplyResult{}, fmt.Errorf("applyGraph: edge %d %s->%s duplicates a parent-child relationship with dependency type %q", i, fromID, toID, depType)
}
if parentDepPairs[depPairKey(toID, fromID)] && cycleRelevantDepType(depType) {
return GraphApplyResult{}, fmt.Errorf("applyGraph: edge %d %s->%s creates a blocking reverse of a parent-child relationship", i, fromID, toID)
}
dep, err := types.NewGraphEdgeDependency(fromID, toID, depType, edge.Gate, edge.SpawnerKey, edge.SpawnerID, edge.ThreadID, keyToID)
if err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: edge %d: %w", i, err)
}
if err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp}); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: edge %d (%s -> %s): %w", i, fromID, toID, err)
}
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 {View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped %w error to identify the root cause (not-found vs constraint vs storage).
- Verify every edge endpoint key exists in the plan's nodes and was created in an earlier phase before edges are applied.
- Ensure the plan's wisp/non-wisp flag matches the actual target table for both endpoints (check UseWispsTable handling).
- If re-applying, make the plan idempotent or clear already-applied edges first.
- Retry after resolving transient Dolt/storage connectivity errors.
Example fix
// before: edge references a key absent from the plan's created nodes
{"edges": [{"fromKey": "bd-99", "toKey": "bd-100", "type": "blocks"}]}
// after: ensure bd-99/bd-100 are defined as nodes in the same plan or already exist
{"nodes": [{"key": "bd-99"}, {"key": "bd-100"}], "edges": [{"fromKey": "bd-99", "toKey": "bd-100", "type": "blocks"}]} Defensive patterns
Strategy: validation
Validate before calling
// Pre-check: every edge endpoint must exist (or be a plan node) before apply
for _, e := range plan.Edges {
if !keysInPlanOrDB(e.FromKey) || !keysInPlanOrDB(e.ToKey) {
return fmt.Errorf("edge %s->%s references unknown issue", e.FromKey, e.ToKey)
}
} Type guard
func edgeEndpointsResolved(e Edge, keyToID map[string]string) bool {
return resolveEdgeRef(e.FromKey, e.FromID, keyToID) != "" &&
resolveEdgeRef(e.ToKey, e.ToID, keyToID) != ""
} Try / catch
if err := bd.GraphApply(ctx, plan); err != nil {
var edgeErr *graphEdgeError
if errors.As(err, &edgeErr) {
log.Printf("edge %d (%s -> %s) failed: %v", edgeErr.Index, edgeErr.From, edgeErr.To, errors.Unwrap(err))
}
return err
} Prevention
- Validate all edge endpoint keys against plan nodes plus existing issues before apply
- Keep wisp/non-wisp usage consistent between nodes and edges
- Make plans idempotent to survive re-application
- Check database connectivity before large applies
When it happens
Trigger: Calling bd graph apply (or the embedded applyGraph path) with a plan whose edges reference issues where the Insert violates constraints: target issue not found in the same table (issues vs wisps mismatch when useWisp is wrong), a duplicate dependency edge, or an underlying Dolt/storage error during Insert.
Common situations: Applying a plan generated against a different database state (edges pointing at issues that were deleted or not created in an earlier phase); mixed wisp/non-wisp nodes where the UseWispsTable flag doesn't match where both endpoints live; network/DB failures during a large apply; re-applying a plan that already inserted the edge under a unique constraint.
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/f5ebe26a751eee41.
Report an issue: GitHub.