gastownhall/beads · error
set labels: id must not be empty
Error message
set labels: id must not be empty
What it means
Thrown by setMany (SetLabels / SetWispLabels) when the ID is empty. SetLabels replaces the full label set, so it must first know which record to operate on; an empty ID is rejected before listing current labels. Input validation, not a storage error.
Source
Thrown at internal/storage/domain/label.go:151
}
if err := u.labelRepo.Delete(ctx, id, label, actor, opts); err != nil {
return fmt.Errorf("remove labels: %s: %w", label, err)
}
}
return nil
}
func (u *labelUseCaseImpl) SetLabels(ctx context.Context, issueID string, labels []string, actor string) error {
return u.setMany(ctx, issueID, labels, actor, false)
}
func (u *labelUseCaseImpl) SetWispLabels(ctx context.Context, wispID string, labels []string, actor string) error {
return u.setMany(ctx, wispID, labels, actor, true)
}
func (u *labelUseCaseImpl) setMany(ctx context.Context, id string, labels []string, actor string, useWisp bool) error {
if id == "" {
return fmt.Errorf("set labels: id must not be empty")
}
opts := LabelOpts{UseWispsTable: useWisp}
current, err := u.labelRepo.List(ctx, id, opts)
if err != nil {
return fmt.Errorf("set labels: list current: %w", err)
}
desired := make(map[string]bool, len(labels))
for _, l := range labels {
if l != "" {
desired[l] = true
}
}
existing := make(map[string]bool, len(current))
for _, l := range current {
existing[l] = true
if !desired[l] {
if err := u.labelRepo.Delete(ctx, id, l, actor, opts); err != nil {
return fmt.Errorf("set labels: remove %s: %w", l, err)View on GitHub (pinned to 71377f2769)
Solutions
- Create/locate the issue first and use its returned ID
- Guard the call with a non-empty ID check
- Fix the upstream producer of the ID variable
- For wisps, pass the wisp ID to SetWispLabels
Example fix
// before
store.SetLabels(ctx, cfg.IssueID, desired, actor) // IssueID often ""
// after
if cfg.IssueID == "" {
return fmt.Errorf("IssueID not set in config")
}
store.SetLabels(ctx, cfg.IssueID, desired, actor) Defensive patterns
Strategy: validation
Validate before calling
if id == "" {
return fmt.Errorf("cannot set labels: issue id is empty")
}
if err := store.SetLabels(ctx, id, labels, actor); err != nil { ... } Prevention
- Create/locate the issue before setting labels and use its returned ID
- Validate config fields that supply IDs are populated
- Never hardcode empty placeholders in generated code paths
- Match wisp APIs to wisp IDs
When it happens
Trigger: SetLabels(ctx, "", labels, actor) or SetWispLabels(ctx, "", labels, actor); an ID variable left empty by a failed creation, missing CLI flag, or JSON field omission.
Common situations: Sync tools computing a desired label set for records that were never created; template pipelines where the ID placeholder did not interpolate; renaming refactor left an ID field unset.
Related errors
- add labels: id must not be empty
- remove labels: id must not be empty
- get labels: id must not be empty
- db: Exists: id must not be empty
- db: LabelSQLRepository.Insert: issueID must not be empty
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b91462b8d24da3ab.
Report an issue: GitHub.