gastownhall/beads · error
db: DependencySQLRepository.ValidateBlockingHierarchy: dep m
Error message
db: DependencySQLRepository.ValidateBlockingHierarchy: dep must not be nil
What it means
ValidateBlockingHierarchy returns this error when the dep argument is nil. After the nil guard it skips validation for external dependency targets and otherwise runs CheckBlockingHierarchyInTx to ensure adding the dependency would not create an invalid blocking hierarchy (e.g. a cycle or a blocker violating hierarchy rules). Called by Insert during dependency creation.
Source
Thrown at internal/storage/domain/db/dependency.go:286
}
func (r *dependencySQLRepositoryImpl) rowExists(ctx context.Context, table, id string) (bool, error) {
var probe int
//nolint:gosec // G201: table is one of the two hardcoded plane tables
err := r.runner.QueryRowContext(ctx, fmt.Sprintf("SELECT 1 FROM %s WHERE id = ? LIMIT 1", table), id).Scan(&probe)
switch {
case err == nil:
return true, nil
case errors.Is(err, sql.ErrNoRows):
return false, nil
default:
return false, err
}
}
func (r *dependencySQLRepositoryImpl) ValidateBlockingHierarchy(ctx context.Context, dep *types.Dependency) error {
if dep == nil {
return errors.New("db: DependencySQLRepository.ValidateBlockingHierarchy: dep must not be nil")
}
if issueops.IsExternalDepTarget(dep.IssueID, dep.DependsOnID) {
return nil
}
return issueops.CheckBlockingHierarchyInTx(ctx, r.runner, dep, nil)
}
// markDirectBlockedSource mirrors issueops.markDirectBlockingDependencySourceInTx:
// is_blocked is derived state, and ready-work queries filter on it directly
// (is_blocked = 0), so a blocking edge insert must set it on the source row
// while the target is still open. updated_at is pinned because recomputing
// derived state is not an edit.
func (r *dependencySQLRepositoryImpl) markDirectBlockedSource(ctx context.Context, source string, srcIsWisp bool, target, targetCol string) error {
sourceTable := "issues"
if srcIsWisp {
sourceTable = "wisps"
}
var targetTable stringView on GitHub (pinned to 71377f2769)
Solutions
- Ensure callers construct a valid *types.Dependency before validation/insert.
- Fix the upstream nil-producing path (failed lookup passed through unchecked).
- For external deps, confirm IsExternalDepTarget applies — validation is skipped for those, but nil is still rejected.
Example fix
// before
repo.ValidateBlockingHierarchy(ctx, nil)
// after
if dep == nil {
return fmt.Errorf("no dependency to validate")
}
repo.ValidateBlockingHierarchy(ctx, dep) Defensive patterns
Strategy: validation
Validate before calling
if dep == nil {
return fmt.Errorf("dependency required for hierarchy validation")
} Type guard
func hasDep(d *types.Dependency) bool { return d != nil && d.IssueID != "" && d.DependsOnID != "" } Try / catch
if err := repo.ValidateBlockingHierarchy(ctx, dep); err != nil {
if strings.Contains(err.Error(), "dep must not be nil") {
// construct dependency before validating
}
// other errors: blocking-hierarchy violations
} Prevention
- Always build a complete *types.Dependency before validate/insert
- Share one validated construction path between Insert and validators
- Check external-dep targets early to skip unnecessary validation
When it happens
Trigger: Insert (or a direct call) passes a nil *types.Dependency to ValidateBlockingHierarchy — same root causes as the nil-Insert case: uninitialized dep pointer from a conditional build path or unchecked lookup.
Common situations: Code path where dependency creation succeeded partially and validation was invoked with a nil record; refactored call sites dropping the nil check upstream.
Related errors
- db: DependencySQLRepository.Insert: dep must not be nil
- db: DependencySQLRepository.Insert: IssueID must not be empt
- db: DependencySQLRepository.Insert: DependsOnID must not be
- no store is open for this workspace
- not found
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c83bbe263284e57c.
Report an issue: GitHub.