{"record":{"id":"f5f8c4888a8d4462","repo":"gastownhall/beads","slug":"iter-dep-metadata-sourceid-must-not-be-empty","errorCode":null,"errorMessage":"iter dep metadata: sourceID must not be empty","messagePattern":"iter dep metadata: sourceID must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/dependency.go","lineNumber":534,"sourceCode":"\nfunc (u *dependencyUseCaseImpl) listWithMetadata(ctx context.Context, sourceID string, filter DepListFilter, useWisp bool) ([]*types.IssueWithDependencyMetadata, error) {\n\tif sourceID == \"\" {\n\t\treturn nil, fmt.Errorf(\"list dep metadata: sourceID must not be empty\")\n\t}\n\tout, err := u.depRepo.ListWithIssueMetadata(ctx, sourceID, DepListOpts{\n\t\tTypes:         filter.Types,\n\t\tDirection:     filter.Direction,\n\t\tUseWispsTable: useWisp,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"list dep metadata: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (u *dependencyUseCaseImpl) iterWithMetadata(ctx context.Context, sourceID string, filter DepListFilter, useWisp bool) (storage.Iter[types.IssueWithDependencyMetadata], error) {\n\tif sourceID == \"\" {\n\t\treturn nil, fmt.Errorf(\"iter dep metadata: sourceID must not be empty\")\n\t}\n\tit, err := u.depRepo.IterWithIssueMetadata(ctx, sourceID, DepListOpts{\n\t\tTypes:         filter.Types,\n\t\tDirection:     filter.Direction,\n\t\tUseWispsTable: useWisp,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"iter dep metadata: %w\", err)\n\t}\n\treturn it, nil\n}\n\nfunc (u *dependencyUseCaseImpl) countByID(ctx context.Context, sourceID string, filter DepListFilter, useWisp bool) (int64, error) {\n\tif sourceID == \"\" {\n\t\treturn 0, fmt.Errorf(\"count by id: sourceID must not be empty\")\n\t}\n\tn, err := u.depRepo.CountByID(ctx, sourceID, DepListOpts{\n\t\tTypes:         filter.Types,","sourceCodeStart":516,"sourceCodeEnd":552,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/dependency.go#L516-L552","documentation":"Validation guard in iterWithMetadata: the source ID for iterator-based dependency metadata listing is empty. Mirrors the listWithMetadata check but for the streaming/iterator API.","triggerScenarios":"Calling IterWithIssueMetadata or IterWispWithIssueMetadata with sourceID == \"\".","commonSituations":"Same as listWithMetadata: unsaved issue objects, failed lookups passed through, or zero-value string IDs in Go callers.","solutions":["Persist/fetch the issue and use its real ID before iterating","Guard with a non-empty check at the call site","Audit paths where issue IDs come from user input or optional lookups"],"exampleFix":"// before\nit, err := u.IterWithIssueMetadata(ctx, srcID, filter) // srcID == \"\"\n// after\nif srcID == \"\" {\n\treturn fmt.Errorf(\"source id required\")\n}\nit, err := u.IterWithIssueMetadata(ctx, srcID, filter)","handlingStrategy":"validation","validationCode":"if sourceID == \"\" {\n\treturn fmt.Errorf(\"cannot iterate dep metadata: source ID is empty\")\n}","typeGuard":"func hasID(id string) bool { return id != \"\" }","tryCatchPattern":"it, err := u.IterWithIssueMetadata(ctx, sourceID, filter)\nif err != nil && strings.Contains(err.Error(), \"iter dep metadata: sourceID\") {\n\treturn fmt.Errorf(\"caller bug: empty source id\")\n}","preventionTips":["Validate IDs before opening iterators","Close iterators promptly to avoid resource leaks masking errors","Source IDs from persisted records only","Do not retry this validation error"],"tags":["validation","dependency","empty-id","iterator"],"backgroundTag":"empty-required-id","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}