{"record":{"id":"a29e41869991cc8f","repo":"gastownhall/beads","slug":"db-labelsqlrepository-list-issueid-must-not-be-e","errorCode":null,"errorMessage":"db: LabelSQLRepository.List: issueID must not be empty","messagePattern":"db: LabelSQLRepository\\.List: issueID must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/storage/domain/db/label.go","lineNumber":126,"sourceCode":"\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Delete %s/%s: rows affected: %w\", issueID, label, err)\n\t}\n\tif rows == 0 {\n\t\treturn nil\n\t}\n\tif err := r.events.Record(ctx, domain.Event{\n\t\tIssueID:  issueID,\n\t\tType:     types.EventLabelRemoved,\n\t\tActor:    actor,\n\t\tOldValue: label,\n\t}, domain.RecordEventOpts{UseWispsTable: opts.UseWispsTable}); err != nil {\n\t\treturn err\n\t}\n\treturn issueops.RecordEventInTx(ctx, r.runner, issueops.EventUpdate, issueID, actor)\n}\n\nfunc (r *labelSQLRepositoryImpl) List(ctx context.Context, issueID string, opts domain.LabelOpts) ([]string, error) {\n\tif issueID == \"\" {\n\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.List: issueID must not be empty\")\n\t}\n\ttable := pickLabelTable(opts.UseWispsTable)\n\t//nolint:gosec // G201: table is one of two hardcoded constants\n\trows, err := r.runner.QueryContext(ctx,\n\t\tfmt.Sprintf(\"SELECT label FROM %s WHERE issue_id = ? ORDER BY label\", table),\n\t\tissueID,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.List %s: %w\", issueID, err)\n\t}\n\tdefer rows.Close()\n\n\tvar out []string\n\tfor rows.Next() {\n\t\tvar label string\n\t\tif err := rows.Scan(&label); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.List: scan: %w\", err)\n\t\t}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/label.go#L108-L144","documentation":"Input validation error thrown by LabelSQLRepository.List when issueID is empty. Listing labels for an empty ID is meaningless and would either error in SQL or return unrelated rows, so the repository rejects the call immediately with a nil result.","triggerScenarios":"Calling List(ctx, \"\", opts) — from a zero-value issue struct, a lookup that failed upstream and returned an empty ID, or argument misordering.","commonSituations":"Code path that ignores an earlier error and proceeds with an empty issueID; JSON payloads missing the id field; batch jobs iterating records where one record has no ID.","solutions":["Populate issueID before calling List","Return early on upstream errors instead of continuing with empty ID","Validate the issue record structure before repository calls"],"exampleFix":"// before\nlabels, _ := issueRepo.Get(ctx, id)\nout, _ := labelRepo.List(ctx, issue.ID, opts) // issue may be zero-value\n// after\nif err != nil { return err }\nif issue.ID == \"\" { return fmt.Errorf(\"issue not loaded\") }\nout, err := labelRepo.List(ctx, issue.ID, opts)","handlingStrategy":"validation","validationCode":"if issueID == \"\" { return fmt.Errorf(\"cannot list labels: issueID required\") }","typeGuard":"func hasIssueID(i Issue) bool { return i.ID != \"\" }","tryCatchPattern":"labels, err := repo.List(ctx, issueID, opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"issueID must not be empty\") { return nil, fmt.Errorf(\"issue not loaded before List\") }\n    return nil, err\n}","preventionTips":["Check upstream errors before using issue structs","Validate issueID before any repository call","Ensure deserialized payloads include the id field","Add unit tests for zero-value struct paths"],"tags":["validation","empty-input","repository"],"backgroundTag":"empty-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}