gastownhall/beads · error
reopen: actor must not be empty
Error message
reopen: actor must not be empty
What it means
A guard error thrown by the reopen() use case when the actor argument is empty. Reopen events are attributed to an actor, so the library rejects empty identities to keep the audit trail meaningful.
Source
Thrown at internal/storage/domain/issue.go:1715
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
}
func (u *issueUseCaseImpl) ClaimIssueIfOpen(ctx context.Context, id, actor string) (ClaimResult, error) {
return u.claim(ctx, id, actor, false)
}View on GitHub (pinned to 71377f2769)
Solutions
- Pass a non-empty actor (authenticated user, service account, or 'system' default).
- Set the identity-providing environment variable in the runtime context.
- Validate actor before the call and surface a clear configuration error.
Example fix
// before
usecase.ReopenIssue(ctx, id, params, "")
// after
if actor == "" { actor = "automation@service" }
usecase.ReopenIssue(ctx, id, params, actor) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(actor) == "" {
return fmt.Errorf("reopen: actor must not be empty")
} Type guard
func validActor(a string) bool { return strings.TrimSpace(a) != "" } Try / catch
if err := run(); err != nil {
if strings.Contains(err.Error(), "actor must not be empty") {
return fmt.Errorf("configure an actor identity before reopening")
}
return err
} Prevention
- Resolve actor once at startup with a sane default (e.g. service account).
- Ensure identity env vars exist in headless environments.
- Thread the actor explicitly through wrapper functions rather than defaulting to "".
- Add a smoke test asserting mutations fail loudly without identity.
When it happens
Trigger: Calling ReopenIssue / ReopenWisp with actor="" — e.g. missing identity in a headless environment, an integration that forgot to pass the actor through, or an empty default in a wrapper function.
Common situations: CI jobs without user identity env vars; service scripts calling reopen with a hardcoded empty actor; webhooks forwarding payloads that omit the acting user.
Related errors
- reopen: id must not be empty
- CountOpenChildren: id must not be empty
- no store is open for this workspace
- not found
- no absolute native user directory is available
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/19a82316e1d7f6cb.
Report an issue: GitHub.