gastownhall/beads · error
add dep: IssueID and DependsOnID must be non-empty
Error message
add dep: IssueID and DependsOnID must be non-empty
What it means
A validation error from the dependency use case: the Dependency struct was non-nil but IssueID or DependsOnID was empty. A dependency edge requires both endpoints, so the call is rejected before any repository or cycle checks run.
Source
Thrown at internal/storage/domain/dependency.go:276
depRepo DependencySQLRepository
}
var _ DependencyUseCase = (*dependencyUseCaseImpl)(nil)
func (u *dependencyUseCaseImpl) AddDependency(ctx context.Context, dep *types.Dependency, actor string) error {
return u.add(ctx, dep, actor, false)
}
func (u *dependencyUseCaseImpl) AddWispDependency(ctx context.Context, dep *types.Dependency, actor string) error {
return u.add(ctx, dep, actor, true)
}
func (u *dependencyUseCaseImpl) add(ctx context.Context, dep *types.Dependency, actor string, useWisp bool) error {
if dep == nil {
return fmt.Errorf("add dep: dep must not be nil")
}
if dep.IssueID == "" || dep.DependsOnID == "" {
return fmt.Errorf("add dep: IssueID and DependsOnID must be non-empty")
}
// Self-dependency guard mirrors issueops.CheckDependencyCycleInTx: it is
// checked BEFORE the cycle probe and for ALL dep types, and emits the
// dedicated self-dep message. A blocking self-edge otherwise trips HasCycle
// and would report the wrong (cycle) error (#4547 F-1).
if dep.IssueID == dep.DependsOnID {
return fmt.Errorf("%w: %s cannot depend on itself", ErrSelfDependency, dep.IssueID)
}
if err := u.depRepo.ValidateBlockingHierarchy(ctx, dep); err != nil {
var hierarchyConflict *DependencyHierarchyConflictError
if errors.As(err, &hierarchyConflict) {
return err
}
return fmt.Errorf("add dep: hierarchy check: %w", err)
}
if types.IsSchedulingEdge(dep.Type) {View on GitHub (pinned to 71377f2769)
Solutions
- Set both IssueID and DependsOnID on the Dependency before calling
- Validate both IDs are non-empty in the caller prior to the API call
- Fix the data source (CLI args, JSON, env) that yielded an empty ID
Example fix
// before
dep := &types.Dependency{IssueID: issueID} // DependsOnID missing
err := uc.AddWispDependency(ctx, dep, actor)
// after
if issueID == "" || dependsOnID == "" { return fmt.Errorf("both issue IDs required") }
dep := &types.Dependency{IssueID: issueID, DependsOnID: dependsOnID}
err := uc.AddWispDependency(ctx, dep, actor) Defensive patterns
Strategy: validation
Validate before calling
if dep == nil || dep.IssueID == "" || dep.DependsOnID == "" {
return fmt.Errorf("dependency requires non-empty IssueID and DependsOnID")
} Type guard
func isCompleteDependency(dep *types.Dependency) bool {
return dep != nil && dep.IssueID != "" && dep.DependsOnID != ""
} Prevention
- Validate both IDs at the CLI/UI boundary before constructing the Dependency
- Check for empty shell variable interpolation feeding issue IDs
- Add unit tests for dependency construction from user input
When it happens
Trigger: Calling AddDependency/AddWispDependency with a &types.Dependency{} where IssueID=="" or DependsOnID=="" — e.g. fields not set after construction, or sourced from empty CLI flags/env/JSON fields.
Common situations: Script or command omitted one of the two issue IDs; parsing a dependency record with a missing field; empty variable interpolation in a shell pipeline feeding bd.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- add dep: dep must not be nil
- proxy.ForceStopUnverified: at most one options value is allo
- db: DependencySQLRepository.Insert: dep must not be nil
- db: DependencySQLRepository.Insert: IssueID must not be empt
- db: DependencySQLRepository.Insert: DependsOnID must not be
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a8a99b0456d31cad.
Report an issue: GitHub.