gastownhall/beads · error
reopen: id must not be empty
Error message
reopen: id must not be empty
What it means
A guard error thrown by the reopen() use case (backing ReopenIssue and ReopenWisp) when the issue ID argument is empty. Like the close path, the library fails fast because an empty ID can never identify a row to reopen.
Source
Thrown at internal/storage/domain/issue.go:1712
return CloseIssueResult{}, fmt.Errorf("close %s: reload: %w", id, err)
}
return CloseIssueResult{
Issue: issue,
Closed: !row.AlreadyClosed,
}, nil
}
func (u *issueUseCaseImpl) ReopenIssue(ctx context.Context, id string, params ReopenIssueParams, actor string) (ReopenIssueResult, error) {
return u.reopen(ctx, id, params, actor, false)
}
func (u *issueUseCaseImpl) ReopenWisp(ctx context.Context, id string, params ReopenIssueParams, actor string) (ReopenIssueResult, error) {
return u.reopen(ctx, id, params, actor, true)
}
func (u *issueUseCaseImpl) reopen(ctx context.Context, id string, params ReopenIssueParams, actor string, useWisp bool) (ReopenIssueResult, error) {
if id == "" {
return ReopenIssueResult{}, fmt.Errorf("reopen: id must not be empty")
}
if actor == "" {
return ReopenIssueResult{}, fmt.Errorf("reopen: actor must not be empty")
}
row, err := u.issueRepo.Reopen(ctx, id, ReopenRowParams{Reason: params.Reason}, actor, IssueTableOpts{UseWispsTable: useWisp})
if err != nil {
return ReopenIssueResult{}, fmt.Errorf("reopen %s: %w", id, err)
}
issue, err := u.issueRepo.Get(ctx, id, IssueTableOpts{UseWispsTable: row.IsWisp})
if err != nil {
return ReopenIssueResult{}, fmt.Errorf("reopen %s: reload: %w", id, err)
}
return ReopenIssueResult{
Issue: issue,
Reopened: row.Updated,
}, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Supply a valid issue ID before invoking ReopenIssue.
- Filter empty IDs out of batch inputs before looping reopen calls.
- Validate id != "" at the boundary (CLI/parser) and emit a clear user-facing message.
Example fix
// before
usecase.ReopenIssue(ctx, id, params, actor) // id == ""
// after
if id == "" { return fmt.Errorf("reopen: issue id required") }
usecase.ReopenIssue(ctx, id, params, actor) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(id) == "" {
return fmt.Errorf("reopen: issue id must not be empty")
} Type guard
func validIssueID(id string) bool { return strings.TrimSpace(id) != "" } Try / catch
if err := run(); err != nil {
if strings.Contains(err.Error(), "reopen: id must not be empty") {
return fmt.Errorf("reopen requires an issue ID")
}
return err
} Prevention
- Validate IDs at the CLI/parser boundary.
- Skip empty IDs in batch reopen loops with a warning.
- Use constructors that reject empty identifiers.
- Fail fast with a clear message before touching storage.
When it happens
Trigger: Calling ReopenIssue / ReopenWisp with id="" — typically an unset variable, empty CLI flag, or blank field from a parsed input passed straight through to the use case.
Common situations: Scripts reopening issues from a list where one entry had an empty ID; misconfigured automation not resolving the issue reference; copy/paste of an invocation with the ID argument dropped.
Related errors
- reopen: actor must not be empty
- CountOpenChildren: id must not be empty
- db: Exists: id must not be empty
- list dep metadata: sourceID must not be empty
- iter dep metadata: sourceID must not be empty
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c7a78be1173fb210.
Report an issue: GitHub.