gastownhall/beads · error
reopen: actor and issue ID must not be empty
Error message
reopen: actor and issue ID must not be empty
What it means
validateReopenRequest requires a non-empty Actor and IssueID on every ReopenRequest, wrapping this rejection in publicops.ErrValidation. Reopening records who performed the action and on which issue.
Source
Thrown at internal/storage/uow/issue_operations.go:581
for _, key := range keys {
if err := storage.ValidateMetadataKey(key); err != nil {
return err
}
if !json.Valid(metadata.Set[key]) {
return fmt.Errorf("metadata value for key %q is not valid JSON", key)
}
}
for _, key := range metadata.Unset {
if err := storage.ValidateMetadataKey(key); err != nil {
return err
}
}
return nil
}
func validateReopenRequest(request publicops.ReopenRequest) error {
if request.Actor == "" || request.IssueID == "" {
return validationError(fmt.Errorf("reopen: actor and issue ID must not be empty"))
}
return nil
}
func semanticIssueEqual(left, right *types.Issue) bool {
if left == nil || right == nil {
return left == right
}
leftCopy := *left
rightCopy := *right
leftCopy.UpdatedAt, rightCopy.UpdatedAt = time.Time{}, time.Time{}
leftCopy.RowVersion, rightCopy.RowVersion = 0, 0
return reflect.DeepEqual(leftCopy, rightCopy)
}
View on GitHub (pinned to 71377f2769)
Solutions
- Set request.Actor to the acting identity before calling Reopen
- Set request.IssueID to the target issue key
- Guard the call site: skip or fix requests with empty fields
- Trace where the empty value originates (config, env, parsing) and add a default or error
Example fix
// before
req := publicops.ReopenRequest{IssueID: id}
// after
req := publicops.ReopenRequest{Actor: actor, IssueID: id}
if req.Actor == "" || req.IssueID == "" { return fmt.Errorf("reopen aborted: missing actor/id") } Defensive patterns
Strategy: validation
Validate before calling
func validReopen(req publicops.ReopenRequest) error {
if req.Actor == "" { return fmt.Errorf("actor required") }
if req.IssueID == "" { return fmt.Errorf("issue ID required") }
return nil
} Type guard
func reopenRequestComplete(req publicops.ReopenRequest) bool {
return req.Actor != "" && req.IssueID != ""
} Try / catch
if err := uc.Reopen(ctx, req); err != nil {
if errors.Is(err, publicops.ErrValidation) {
// input bug: populate Actor/IssueID, do not retry blindly
return err
}
return err
} Prevention
- Require actor as a parameter in reopen helper functions
- Validate IDs parsed from user input before building ReopenRequest
- Set a default actor for automated reopen flows
- Keep request construction centralized and unit-test field completeness
When it happens
Trigger: Calling Reopen with a publicops.ReopenRequest where request.Actor == "" or request.IssueID == "".
Common situations: A reopen automation with no actor identity configured, IDs parsed from input that yielded empty strings, or a request struct partially populated after copy-paste from another operation.
Related errors
- update: actor and issue ID must not be empty
- close: actor and issue 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/d420857feb741464.
Report an issue: GitHub.