{"record":{"id":"6e59472b8c139325","repo":"gastownhall/beads","slug":"reopen-s-w","errorCode":null,"errorMessage":"reopen %s: %w","messagePattern":"reopen (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1719,"sourceCode":"\nfunc (u *issueUseCaseImpl) ReopenIssue(ctx context.Context, id string, params ReopenIssueParams, actor string) (ReopenIssueResult, error) {\n\treturn u.reopen(ctx, id, params, actor, false)\n}\n\nfunc (u *issueUseCaseImpl) ReopenWisp(ctx context.Context, id string, params ReopenIssueParams, actor string) (ReopenIssueResult, error) {\n\treturn u.reopen(ctx, id, params, actor, true)\n}\n\nfunc (u *issueUseCaseImpl) reopen(ctx context.Context, id string, params ReopenIssueParams, actor string, useWisp bool) (ReopenIssueResult, error) {\n\tif id == \"\" {\n\t\treturn ReopenIssueResult{}, fmt.Errorf(\"reopen: id must not be empty\")\n\t}\n\tif actor == \"\" {\n\t\treturn ReopenIssueResult{}, fmt.Errorf(\"reopen: actor must not be empty\")\n\t}\n\trow, err := u.issueRepo.Reopen(ctx, id, ReopenRowParams{Reason: params.Reason}, actor, IssueTableOpts{UseWispsTable: useWisp})\n\tif err != nil {\n\t\treturn ReopenIssueResult{}, fmt.Errorf(\"reopen %s: %w\", id, err)\n\t}\n\tissue, err := u.issueRepo.Get(ctx, id, IssueTableOpts{UseWispsTable: row.IsWisp})\n\tif err != nil {\n\t\treturn ReopenIssueResult{}, fmt.Errorf(\"reopen %s: reload: %w\", id, err)\n\t}\n\treturn ReopenIssueResult{\n\t\tIssue:    issue,\n\t\tReopened: row.Updated,\n\t}, nil\n}\n\nfunc (u *issueUseCaseImpl) ClaimIssueIfOpen(ctx context.Context, id, actor string) (ClaimResult, error) {\n\treturn u.claim(ctx, id, actor, false)\n}\n\nfunc (u *issueUseCaseImpl) ClaimWispIfOpen(ctx context.Context, id, actor string) (ClaimResult, error) {\n\treturn u.claim(ctx, id, actor, true)\n}","sourceCodeStart":1701,"sourceCodeEnd":1737,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1701-L1737","documentation":"This error wraps any failure from u.issueRepo.Reopen in the reopen() use case — the storage-level state transition from closed back to open failed. The ID is embedded in the message and the underlying repository error (not-found, storage failure) is chained via %w.","triggerScenarios":"Calling ReopenIssue where issueRepo.Reopen(ctx, id, ReopenRowParams, actor, opts) errors: ID not found in the routed table (main vs wisps per useWisp), database failure, or a driver/constraint rejection.","commonSituations":"Reopening an already-deleted or mistyped issue ID; the issue is a wisp but the call routed to the main table (or vice versa); transient DB lock/connectivity failure during the update.","solutions":["Confirm the issue exists and is currently closed via Get before reopening.","Check the wrapped cause: not-found means bad ID or wrong table routing; fix the ID or wisp flag.","Retry on transient storage errors (locks, connectivity).","If wisp-related, ensure the wisp routing flag matches where the row actually lives."],"exampleFix":"// before\n_, err := usecase.ReopenIssue(ctx, id, params, actor)\n// after\nif _, gerr := usecase.GetIssue(ctx, id); gerr != nil {\n    return fmt.Errorf(\"cannot reopen %s: %w\", id, gerr)\n}\n_, err := usecase.ReopenIssue(ctx, id, params, actor)","handlingStrategy":"validation","validationCode":"issue, err := usecase.GetIssue(ctx, id)\nif err != nil {\n    return fmt.Errorf(\"cannot reopen %s: %w\", id, err)\n}\nif issue.Status != StatusClosed {\n    return fmt.Errorf(\"%s is not closed\", id)\n}","typeGuard":"func isNotFound(err error) bool {\n    return errors.Is(err, ErrNotFound)\n}","tryCatchPattern":"_, err := usecase.ReopenIssue(ctx, id, params, actor)\nif err != nil {\n    if isNotFound(err) {\n        return fmt.Errorf(\"issue %s not found\", id)\n    }\n    if isTransient(err) {\n        return retryReopen(ctx, id, params, actor)\n    }\n    return err\n}","preventionTips":["Verify existence and closed status before reopening.","Match wisp routing flags to where the row lives.","Retry transient storage failures with backoff.","Keep IDs sourced from fresh list output."],"tags":["storage","reopen-issue","wrapped-error","repo-failure"],"backgroundTag":"issue-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}