gastownhall/beads · warning
db: LabelSQLRepository.List: issueID must not be empty
Error message
db: LabelSQLRepository.List: issueID must not be empty
What it means
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.
Source
Thrown at internal/storage/domain/db/label.go:126
return fmt.Errorf("db: LabelSQLRepository.Delete %s/%s: rows affected: %w", issueID, label, err)
}
if rows == 0 {
return nil
}
if err := r.events.Record(ctx, domain.Event{
IssueID: issueID,
Type: types.EventLabelRemoved,
Actor: actor,
OldValue: label,
}, domain.RecordEventOpts{UseWispsTable: opts.UseWispsTable}); err != nil {
return err
}
return issueops.RecordEventInTx(ctx, r.runner, issueops.EventUpdate, issueID, actor)
}
func (r *labelSQLRepositoryImpl) List(ctx context.Context, issueID string, opts domain.LabelOpts) ([]string, error) {
if issueID == "" {
return nil, fmt.Errorf("db: LabelSQLRepository.List: issueID must not be empty")
}
table := pickLabelTable(opts.UseWispsTable)
//nolint:gosec // G201: table is one of two hardcoded constants
rows, err := r.runner.QueryContext(ctx,
fmt.Sprintf("SELECT label FROM %s WHERE issue_id = ? ORDER BY label", table),
issueID,
)
if err != nil {
return nil, fmt.Errorf("db: LabelSQLRepository.List %s: %w", issueID, err)
}
defer rows.Close()
var out []string
for rows.Next() {
var label string
if err := rows.Scan(&label); err != nil {
return nil, fmt.Errorf("db: LabelSQLRepository.List: scan: %w", err)
}View on GitHub (pinned to 71377f2769)
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
Example fix
// before
labels, _ := issueRepo.Get(ctx, id)
out, _ := labelRepo.List(ctx, issue.ID, opts) // issue may be zero-value
// after
if err != nil { return err }
if issue.ID == "" { return fmt.Errorf("issue not loaded") }
out, err := labelRepo.List(ctx, issue.ID, opts) Defensive patterns
Strategy: validation
Validate before calling
if issueID == "" { return fmt.Errorf("cannot list labels: issueID required") } Type guard
func hasIssueID(i Issue) bool { return i.ID != "" } Try / catch
labels, err := repo.List(ctx, issueID, opts)
if err != nil {
if strings.Contains(err.Error(), "issueID must not be empty") { return nil, fmt.Errorf("issue not loaded before List") }
return nil, err
} Prevention
- 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
When it happens
Trigger: Calling List(ctx, "", opts) — from a zero-value issue struct, a lookup that failed upstream and returned an empty ID, or argument misordering.
Common situations: 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.
Related errors
- db: LabelSQLRepository.Delete: issueID must not be empty
- db: LabelSQLRepository.Delete: label must not be empty
- %s cannot be empty
- no rules to compact
- memory content cannot be empty
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a29e41869991cc8f.
Report an issue: GitHub.