{"record":{"id":"c0ca8cd87c0990a7","repo":"gastownhall/beads","slug":"claimreadywisp-w","errorCode":null,"errorMessage":"ClaimReadyWisp: %w","messagePattern":"ClaimReadyWisp: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1807,"sourceCode":"}\n\nfunc (u *issueUseCaseImpl) ClaimReadyWisp(ctx context.Context, filter types.WorkFilter, actor string) (ClaimReadyResult, error) {\n\treturn u.claimReady(ctx, filter, actor, true)\n}\n\nfunc (u *issueUseCaseImpl) claimReady(ctx context.Context, filter types.WorkFilter, actor string, useWisp bool) (ClaimReadyResult, error) {\n\tvar (\n\t\tissue *types.Issue\n\t\terr   error\n\t)\n\tif useWisp {\n\t\tissue, err = u.issueRepo.ClaimReadyWisp(ctx, filter, actor)\n\t} else {\n\t\tissue, err = u.issueRepo.ClaimReadyIssue(ctx, filter, actor)\n\t}\n\tif err != nil {\n\t\tif useWisp {\n\t\t\treturn ClaimReadyResult{}, fmt.Errorf(\"ClaimReadyWisp: %w\", err)\n\t\t}\n\t\treturn ClaimReadyResult{}, fmt.Errorf(\"ClaimReadyIssue: %w\", err)\n\t}\n\treturn ClaimReadyResult{Issue: issue, Claimed: issue != nil}, nil\n}\n\nfunc (u *issueUseCaseImpl) GetBlockedIssues(ctx context.Context, filter types.WorkFilter) ([]*types.BlockedIssue, error) {\n\tout, err := u.issueRepo.GetBlockedIssues(ctx, filter)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"GetBlockedIssues: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (u *issueUseCaseImpl) GetStatistics(ctx context.Context) (*types.Statistics, error) {\n\tout, err := u.issueRepo.GetStatistics(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"GetStatistics: %w\", err)","sourceCodeStart":1789,"sourceCodeEnd":1825,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1789-L1825","documentation":"Wrapped error from the claimReady flow when the wisp-specific repository method ClaimReadyWisp fails. The use-case branches on useWisp and labels the failure 'ClaimReadyWisp:' so callers can tell which storage path failed. The repository error is preserved via %w.","triggerScenarios":"Calling ClaimReadyIssue / ClaimReadyIssueWisp with useWisp=true when issueRepo.ClaimReadyWisp(ctx, filter, actor) errors — e.g. no eligible wisp row can be locked/updated, filter is invalid for wisps, or the storage write fails.","commonSituations":"Agent work-claiming (bd ready / claim) against the wisps table with filters no wisp satisfies but expressed invalidly; concurrent claimers causing row-lock conflicts; actor string issues in storage.","solutions":["Inspect the wrapped error after 'ClaimReadyWisp:' for the root cause","Validate the WorkFilter fields are applicable to wisps before claiming","Retry on transient lock/conflict errors; claims are idempotent per issue","Fall back to the non-wisp claim path if wisps are not enabled"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if filter == (types.WorkFilter{}) || useWisp && !wispsEnabled {\n    return fmt.Errorf(\"invalid claim configuration\")\n}","typeGuard":null,"tryCatchPattern":"res, err := uc.ClaimReadyIssueWisp(ctx, filter, actor)\nif err != nil {\n    if isTransient(err) {\n        time.Sleep(backoff); goto retry\n    }\n    log.Warnf(\"claim failed: %v\", err)\n    return ClaimReadyResult{}\n}","preventionTips":["Validate WorkFilter fields are applicable to the wisp path before claiming","Use bounded retries with backoff for claim contention","Ensure only one claimer process races per issue where possible","Confirm wisps are enabled before using the wisp claim path"],"tags":["go","storage","error-wrapping","claim-ready","wisp"],"backgroundTag":"repository-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}