{"record":{"id":"854a7b8ebf94d67f","repo":"gastownhall/beads","slug":"getepicseligibleforclosure-w","errorCode":null,"errorMessage":"GetEpicsEligibleForClosure: %w","messagePattern":"GetEpicsEligibleForClosure: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1873,"sourceCode":"\tout, err := u.issueRepo.IterEvents(ctx, id, limit)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"IterEvents: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (u *issueUseCaseImpl) GetStaleIssues(ctx context.Context, filter types.StaleFilter) ([]*types.Issue, error) {\n\tout, err := u.issueRepo.GetStaleIssues(ctx, filter)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"GetStaleIssues: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (u *issueUseCaseImpl) GetEpicsEligibleForClosure(ctx context.Context) ([]*types.EpicStatus, error) {\n\tout, err := u.issueRepo.GetEpicsEligibleForClosure(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"GetEpicsEligibleForClosure: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (u *issueUseCaseImpl) Unclaim(ctx context.Context, id, actor string, force bool) error {\n\tif id == \"\" {\n\t\treturn fmt.Errorf(\"Unclaim: id must not be empty\")\n\t}\n\tif err := u.issueRepo.UnclaimIssue(ctx, id, actor, force); err != nil {\n\t\treturn fmt.Errorf(\"Unclaim: %w\", err)\n\t}\n\treturn nil\n}\n\n// UnclaimIfAssignee is the compare-and-swap release: it clears the claim only\n// while the issue is still assigned to expectedAssignee, and otherwise returns\n// storage.ErrAssigneeMismatch having written nothing. It is the conditional\n// twin of Unclaim and runs the SAME transition (assignee cleared, status","sourceCodeStart":1855,"sourceCodeEnd":1891,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1855-L1891","documentation":"Wrapped error from GetEpicsEligibleForClosure in the issue use-case layer. The repo query for epics whose children are all closed is delegated to issueRepo; any failure is prefixed with \"GetEpicsEligibleForClosure: \". It signals a storage-layer failure, not a caller-input problem (the method takes no arguments).","triggerScenarios":"Calling GetEpicsEligibleForClosure(ctx) when the repository query fails: database unavailable, schema/query error, or transaction conflict.","commonSituations":"Running epic-closure sweeps in scripts or hooks while the Dolt database is down or the schema is being migrated.","solutions":["Unwrap the error to find the underlying repository cause","Check database connectivity and schema integrity","Retry the sweep if the underlying error is transient"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"epics, err := uc.GetEpicsEligibleForClosure(ctx)\nif err != nil {\n\tif isTransient(err) {\n\t\treturn retryWithBackoff(op)\n\t}\n\treturn err\n}","preventionTips":["Run epic-closure sweeps after DB health checks pass","Avoid running the sweep during schema migrations","Retry with backoff since the call takes no parameters and is idempotent"],"tags":["storage","error-wrapping","epics"],"backgroundTag":"repo-error-wrapping","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}