{"record":{"id":"66bf4ef866ab720a","repo":"gastownhall/beads","slug":"countopenchildren-id-must-not-be-empty","errorCode":null,"errorMessage":"CountOpenChildren: id must not be empty","messagePattern":"CountOpenChildren: id must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1749,"sourceCode":"func (u *issueUseCaseImpl) ClaimIssueIfOpen(ctx context.Context, id, actor string) (ClaimResult, error) {\n\treturn u.claim(ctx, id, actor, false)\n}\n\nfunc (u *issueUseCaseImpl) ClaimWispIfOpen(ctx context.Context, id, actor string) (ClaimResult, error) {\n\treturn u.claim(ctx, id, actor, true)\n}\n\nfunc (u *issueUseCaseImpl) CountOpenChildren(ctx context.Context, id string) (int, error) {\n\treturn u.countOpenChildren(ctx, id, false)\n}\n\nfunc (u *issueUseCaseImpl) CountOpenWispChildren(ctx context.Context, id string) (int, error) {\n\treturn u.countOpenChildren(ctx, id, true)\n}\n\nfunc (u *issueUseCaseImpl) countOpenChildren(ctx context.Context, id string, useWisp bool) (int, error) {\n\tif id == \"\" {\n\t\treturn 0, fmt.Errorf(\"CountOpenChildren: id must not be empty\")\n\t}\n\tchildren, err := u.depRepo.ListWithIssueMetadata(ctx, id, DepListOpts{\n\t\tTypes:         []types.DependencyType{types.DepParentChild},\n\t\tDirection:     DepDirectionIn,\n\t\tUseWispsTable: useWisp,\n\t})\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"CountOpenChildren %s: %w\", id, err)\n\t}\n\topen := 0\n\tfor _, child := range children {\n\t\tif child.Status != types.StatusClosed {\n\t\t\topen++\n\t\t}\n\t}\n\treturn open, nil\n}\n","sourceCodeStart":1731,"sourceCodeEnd":1767,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1731-L1767","documentation":"A guard error thrown by countOpenChildren() (backing CountOpenChildren and CountOpenWispChildren) when the issue ID is empty. The method counts open child issues via dependency edges inbound of type parent-child, and an empty ID can never match any parent, so the library fails fast.","triggerScenarios":"Calling CountOpenChildren / CountOpenWispChildren with id=\"\" — e.g. an empty parent ID passed from close-time checks, or a caller computing dependencies for an unresolved/blank issue reference.","commonSituations":"Close workflows computing 'open children' warnings for an issue whose ID was lost upstream; batch scripts iterating entries with blank IDs; automation passing an empty variable after a failed lookup.","solutions":["Provide a valid parent issue ID before counting children.","Validate id != \"\" at the call site or skip the count for blank IDs in batch loops.","Fix the upstream lookup that produced the empty ID (failed Get, empty field)."],"exampleFix":"// before\ncount, err := usecase.CountOpenChildren(ctx, id) // id == \"\"\n// after\nif id == \"\" { return 0, fmt.Errorf(\"parent id required\") }\ncount, err := usecase.CountOpenChildren(ctx, id)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(id) == \"\" {\n    return 0, fmt.Errorf(\"count children: parent id must not be empty\")\n}","typeGuard":"func validIssueID(id string) bool { return strings.TrimSpace(id) != \"\" }","tryCatchPattern":"n, err := usecase.CountOpenChildren(ctx, id)\nif err != nil {\n    if strings.Contains(err.Error(), \"id must not be empty\") {\n        return 0, fmt.Errorf(\"skipping child count: no parent ID\")\n    }\n    return err\n}","preventionTips":["Resolve the parent ID before computing dependency counts.","Guard batch loops against blank IDs.","Propagate failed lookups as errors instead of empty strings.","Validate inputs at the command/service boundary."],"tags":["validation","dependencies","empty-id","guard"],"backgroundTag":"empty-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}