{"record":{"id":"a8a99b0456d31cad","repo":"gastownhall/beads","slug":"add-dep-issueid-and-dependsonid-must-be-non-empty","errorCode":null,"errorMessage":"add dep: IssueID and DependsOnID must be non-empty","messagePattern":"add dep: IssueID and DependsOnID must be non-empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/dependency.go","lineNumber":276,"sourceCode":"\tdepRepo DependencySQLRepository\n}\n\nvar _ DependencyUseCase = (*dependencyUseCaseImpl)(nil)\n\nfunc (u *dependencyUseCaseImpl) AddDependency(ctx context.Context, dep *types.Dependency, actor string) error {\n\treturn u.add(ctx, dep, actor, false)\n}\n\nfunc (u *dependencyUseCaseImpl) AddWispDependency(ctx context.Context, dep *types.Dependency, actor string) error {\n\treturn u.add(ctx, dep, actor, true)\n}\n\nfunc (u *dependencyUseCaseImpl) add(ctx context.Context, dep *types.Dependency, actor string, useWisp bool) error {\n\tif dep == nil {\n\t\treturn fmt.Errorf(\"add dep: dep must not be nil\")\n\t}\n\tif dep.IssueID == \"\" || dep.DependsOnID == \"\" {\n\t\treturn fmt.Errorf(\"add dep: IssueID and DependsOnID must be non-empty\")\n\t}\n\n\t// Self-dependency guard mirrors issueops.CheckDependencyCycleInTx: it is\n\t// checked BEFORE the cycle probe and for ALL dep types, and emits the\n\t// dedicated self-dep message. A blocking self-edge otherwise trips HasCycle\n\t// and would report the wrong (cycle) error (#4547 F-1).\n\tif dep.IssueID == dep.DependsOnID {\n\t\treturn fmt.Errorf(\"%w: %s cannot depend on itself\", ErrSelfDependency, dep.IssueID)\n\t}\n\tif err := u.depRepo.ValidateBlockingHierarchy(ctx, dep); err != nil {\n\t\tvar hierarchyConflict *DependencyHierarchyConflictError\n\t\tif errors.As(err, &hierarchyConflict) {\n\t\t\treturn err\n\t\t}\n\t\treturn fmt.Errorf(\"add dep: hierarchy check: %w\", err)\n\t}\n\n\tif types.IsSchedulingEdge(dep.Type) {","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/dependency.go#L258-L294","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ndep := &types.Dependency{IssueID: issueID} // DependsOnID missing\nerr := uc.AddWispDependency(ctx, dep, actor)\n// after\nif issueID == \"\" || dependsOnID == \"\" { return fmt.Errorf(\"both issue IDs required\") }\ndep := &types.Dependency{IssueID: issueID, DependsOnID: dependsOnID}\nerr := uc.AddWispDependency(ctx, dep, actor)","handlingStrategy":"validation","validationCode":"if dep == nil || dep.IssueID == \"\" || dep.DependsOnID == \"\" {\n    return fmt.Errorf(\"dependency requires non-empty IssueID and DependsOnID\")\n}","typeGuard":"func isCompleteDependency(dep *types.Dependency) bool {\n    return dep != nil && dep.IssueID != \"\" && dep.DependsOnID != \"\"\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["validation","dependency","empty-field","api-misuse"],"backgroundTag":"missing-required-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}