{"record":{"id":"e4845fd4b02b4152","repo":"gastownhall/beads","slug":"hydrate-neighbors-wisps-w","errorCode":null,"errorMessage":"hydrate neighbors (wisps): %w","messagePattern":"hydrate neighbors \\(wisps\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":388,"sourceCode":"\n\tif len(neighbors) == 0 {\n\t\treturn out, isWisp, nil\n\t}\n\tids := make([]string, 0, len(neighbors))\n\tfor id := range neighbors {\n\t\tids = append(ids, id)\n\t}\n\n\tfromIssues, err := u.issueRepo.GetByIDs(ctx, ids, IssueTableOpts{})\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"hydrate neighbors (issues): %w\", err)\n\t}\n\tfor _, iss := range fromIssues {\n\t\tout[iss.ID] = iss\n\t}\n\tfromWisps, err := u.issueRepo.GetByIDs(ctx, ids, IssueTableOpts{UseWispsTable: true})\n\tif err != nil && !dberrors.IsTableNotExist(err) {\n\t\treturn nil, nil, fmt.Errorf(\"hydrate neighbors (wisps): %w\", err)\n\t}\n\tfor _, iss := range fromWisps {\n\t\tout[iss.ID] = iss\n\t\tisWisp[iss.ID] = true\n\t}\n\treturn out, isWisp, nil\n}\n\nfunc (u *issueUseCaseImpl) rewriteTextReferences(\n\tctx context.Context, deletedIDs []string,\n\tconnected map[string]*types.Issue, isWisp map[string]bool, actor string,\n) (int, error) {\n\ttouched := make(map[string]bool)\n\tfor _, id := range deletedIDs {\n\t\tpattern := `(^|[^A-Za-z0-9_-])(` + regexp.QuoteMeta(id) + `)($|[^A-Za-z0-9_-])`\n\t\tre := regexp.MustCompile(pattern)\n\t\treplacement := `$1[deleted:` + id + `]$3`\n\t\tfor connID, conn := range connected {","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L370-L406","documentation":"Wraps a failure from issueRepo.GetByIDs against the wisp table (IssueTableOpts{UseWispsTable:true}) during neighbor hydration in collectConnectedIssues. A missing wisp table is tolerated (dberrors.IsTableNotExist), so this error only fires for genuine storage failures on the wisp plane — e.g. a real query error while reading wisp_neighbor rows.","triggerScenarios":"deleteMany/previewDelete with dependency-connected neighbors where the wisps table exists but the bulk GetByIDs on it fails: driver error, connection loss, context cancellation, or malformed query results.","commonSituations":"Mixed durable/wisp stores where the wisp table is present but corrupted; transient Dolt server errors during delete; canceled long deletes; driver version mismatch causing query incompatibility on the wisp table.","solutions":["Inspect the wrapped cause; if it is a table-missing error, verify dberrors.IsTableNotExist handling covers your driver's error shape.","Check database connectivity/locks and retry the delete.","Rerun with a fresh context to rule out cancellation from an upstream request.","If the wisp table is corrupted, repair or recreate the wisp plane (bd doctor) before deleting.","Confirm your storage driver version supports the wisps table schema in use."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// confirm store health before delete\nif err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"store unreachable: %w\", err) }","typeGuard":"func isHydrateWispsErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"hydrate neighbors (wisps)\")\n}","tryCatchPattern":"err := usecase.DeleteMany(ctx, ids)\nif err != nil && strings.Contains(err.Error(), \"hydrate neighbors (wisps)\") {\n    cause := errors.Unwrap(err)\n    if !dberrors.IsTableNotExist(cause) {\n        return fmt.Errorf(\"wisp hydration failed: %w\", cause) // retry or escalate\n    }\n}","preventionTips":["Keep the storage driver version in sync with the wisps-table schema","Retry transient errors once with backoff before failing the whole delete","Monitor Dolt server health for stores using the wisp plane","Run bd doctor periodically to catch wisp-table corruption early"],"tags":["storage","database","wisps","delete"],"backgroundTag":"database-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}