gastownhall/beads · error
add deps: classify sources: %w
Error message
add deps: classify sources: %w
What it means
AddDependencies classifies the batch's source issue IDs into regular issues vs wisps (ephemeral issues) with a single batched repository query (WispSourceIDs) made before any write. This error wraps a failure of that lookup, so the root cause is a storage/repository error (query failure, DB unavailable, context canceled), not a validation problem.
Source
Thrown at internal/storage/domain/dependency.go:714
// types before the hierarchy/cycle probe, so a scheduling self-edge is
// typed as ErrSelfDependency instead of tripping HasCycle (or the final
// CycleThroughEdges gate) and surfacing as a cycle. The message is
// byte-identical to every other self-dep site so the proxied bulk CLI
// (bd dep add / bd link) shows one consistent self-dependency error.
if dep.IssueID == dep.DependsOnID {
return BulkAddDepsResult{}, fmt.Errorf("%w: %s cannot depend on itself", ErrSelfDependency, dep.IssueID)
}
}
sources := make([]string, 0, len(deps))
for _, dep := range deps {
sources = append(sources, dep.IssueID)
}
// One query for the batch, read before the first write. Nothing an edge
// write does moves a source between planes, so the answer stays true for
// the rest of the unit of work.
wispSources, err := u.depRepo.WispSourceIDs(ctx, sources)
if err != nil {
return BulkAddDepsResult{}, fmt.Errorf("add deps: classify sources: %w", err)
}
// Parent-child edges must be visible before blocking edges in the same
// request. The shared repository guard can then evaluate existing + planned
// ancestry without widening #4034 into #4035's combined-graph cycle check.
for phase := 0; phase < 2; phase++ {
parentPhase := phase == 0
for i, dep := range deps {
if (dep.Type == types.DepParentChild) != parentPhase {
continue
}
if err := u.depRepo.ValidateBlockingHierarchy(ctx, dep); err != nil {
var hierarchyConflict *DependencyHierarchyConflictError
if errors.As(err, &hierarchyConflict) {
return BulkAddDepsResult{}, err
}
return BulkAddDepsResult{}, fmt.Errorf("add deps[%d]: hierarchy check: %w", i, err)
}
if !opts.SkipPerEdgeCycleCheck && types.IsSchedulingEdge(dep.Type) {View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped root cause (%w) — usually a Dolt/driver error printed after this prefix
- Verify the .beads database is accessible and not locked by another process (bd doctor)
- Retry the operation with a fresh, non-expired context
Defensive patterns
Strategy: try-catch
Validate before calling
if err := ctx.Err(); err != nil { return err } // ensure live context before the call Try / catch
if _, err := uc.AddDependencies(ctx, deps, opts); err != nil {
if strings.Contains(err.Error(), "classify sources") {
// storage-layer failure; check DB health and retry
}
return err
} Prevention
- Pass a fresh context with an adequate deadline
- Ensure the .beads Dolt database is not locked by another process
- Run bd doctor to verify storage health before large batches
When it happens
Trigger: Calling AddDependencies when u.depRepo.WispSourceIDs(ctx, sources) returns an error — e.g. the Dolt database is unreachable, the connection was closed, or ctx was canceled mid-query.
Common situations: Running bd against a locked or corrupt .beads Dolt database; concurrent process holding a conflicting transaction; context timeout expiring during a large batch on slow storage.
Related errors
- failed to remove relates-to %s -> %s: %w
- failed to get dependencies for %s: %w
- delete: drop deps: %w
- delete: drop wisp deps: %w
- delete: drop sync-plane edges into deleted wisps: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6b315e7ca98ce7e4.
Report an issue: GitHub.