{"record":{"id":"c83bbe263284e57c","repo":"gastownhall/beads","slug":"db-dependencysqlrepository-validateblockinghierar","errorCode":null,"errorMessage":"db: DependencySQLRepository.ValidateBlockingHierarchy: dep must not be nil","messagePattern":"db: DependencySQLRepository\\.ValidateBlockingHierarchy: dep must not be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/dependency.go","lineNumber":286,"sourceCode":"}\n\nfunc (r *dependencySQLRepositoryImpl) rowExists(ctx context.Context, table, id string) (bool, error) {\n\tvar probe int\n\t//nolint:gosec // G201: table is one of the two hardcoded plane tables\n\terr := r.runner.QueryRowContext(ctx, fmt.Sprintf(\"SELECT 1 FROM %s WHERE id = ? LIMIT 1\", table), id).Scan(&probe)\n\tswitch {\n\tcase err == nil:\n\t\treturn true, nil\n\tcase errors.Is(err, sql.ErrNoRows):\n\t\treturn false, nil\n\tdefault:\n\t\treturn false, err\n\t}\n}\n\nfunc (r *dependencySQLRepositoryImpl) ValidateBlockingHierarchy(ctx context.Context, dep *types.Dependency) error {\n\tif dep == nil {\n\t\treturn errors.New(\"db: DependencySQLRepository.ValidateBlockingHierarchy: dep must not be nil\")\n\t}\n\tif issueops.IsExternalDepTarget(dep.IssueID, dep.DependsOnID) {\n\t\treturn nil\n\t}\n\treturn issueops.CheckBlockingHierarchyInTx(ctx, r.runner, dep, nil)\n}\n\n// markDirectBlockedSource mirrors issueops.markDirectBlockingDependencySourceInTx:\n// is_blocked is derived state, and ready-work queries filter on it directly\n// (is_blocked = 0), so a blocking edge insert must set it on the source row\n// while the target is still open. updated_at is pinned because recomputing\n// derived state is not an edit.\nfunc (r *dependencySQLRepositoryImpl) markDirectBlockedSource(ctx context.Context, source string, srcIsWisp bool, target, targetCol string) error {\n\tsourceTable := \"issues\"\n\tif srcIsWisp {\n\t\tsourceTable = \"wisps\"\n\t}\n\tvar targetTable string","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/dependency.go#L268-L304","documentation":"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.","triggerScenarios":"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.","commonSituations":"Code path where dependency creation succeeded partially and validation was invoked with a nil record; refactored call sites dropping the nil check upstream.","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."],"exampleFix":"// before\nrepo.ValidateBlockingHierarchy(ctx, nil)\n// after\nif dep == nil {\n    return fmt.Errorf(\"no dependency to validate\")\n}\nrepo.ValidateBlockingHierarchy(ctx, dep)","handlingStrategy":"validation","validationCode":"if dep == nil {\n    return fmt.Errorf(\"dependency required for hierarchy validation\")\n}","typeGuard":"func hasDep(d *types.Dependency) bool { return d != nil && d.IssueID != \"\" && d.DependsOnID != \"\" }","tryCatchPattern":"if err := repo.ValidateBlockingHierarchy(ctx, dep); err != nil {\n    if strings.Contains(err.Error(), \"dep must not be nil\") {\n        // construct dependency before validating\n    }\n    // other errors: blocking-hierarchy violations\n}","preventionTips":["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"],"tags":["validation","dependency","hierarchy","go","storage"],"backgroundTag":"nil-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}