{"record":{"id":"c8a6ea13adeb0f20","repo":"gastownhall/beads","slug":"hydrate-neighbors-w","errorCode":null,"errorMessage":"hydrate neighbors: %w","messagePattern":"hydrate neighbors: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete_role.go","lineNumber":304,"sourceCode":"\t\t\t}\n\t\t\t_ = rows.Close()\n\t\t\tif err := rows.Err(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"iterate neighbors from %s: %w\", depTable, err)\n\t\t\t}\n\t\t}\n\t}\n\tif len(neighborIDs) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Sorted so the rewrite touches rows in a stable order, which is what\n\t// makes a partially-applied failure reproducible.\n\thydrate := workapi.SortedDeleteIDs(neighborIDs)\n\t// An `external:` target and a target belonging to another repository name\n\t// no row here; GetIssuesByIDsInTx simply does not return them.\n\tissues, err := GetIssuesByIDsInTx(ctx, tx, hydrate, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"hydrate neighbors: %w\", err)\n\t}\n\treturn issues, nil\n}\n\n// RewriteDeletedReferencesInTx replaces every word-boundary occurrence of a\n// deleted id with `[deleted:<id>]` in each neighbor's description, notes,\n// design and acceptance criteria, and reports how many ROWS it changed.\n//\n// Exported because the unit-of-work body needs the same rule and neither\n// implementation may own it: a route that spelled the pattern differently\n// would rewrite a different set of citations for the same deletion.\nfunc RewriteDeletedReferencesInTx(ctx context.Context, tx DBTX, deletedIDs []string, neighbors []*types.Issue, actor string) (int, error) {\n\tif len(neighbors) == 0 {\n\t\treturn 0, nil\n\t}\n\ttouched := make(map[string]bool)\n\tfor _, id := range deletedIDs {\n\t\tre := DeletedReferencePattern(id)","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete_role.go#L286-L322","documentation":"After collecting surviving neighbor ids, deleteNeighborsInTx hydrates them into full Issue rows via GetIssuesByIDsInTx so their text can be rewritten. This wrapper marks a failure in that hydration step. Per the source comment, external: targets and rows belonging to another repository name legitimately resolve to nothing and are simply absent — this error is for genuine lookup failures, not missing cross-repo rows.","triggerScenarios":"deleteNeighborsInTx calls GetIssuesByIDsInTx(hydrate, nil) over sorted neighbor ids and the batched lookup fails — driver error, context cancellation, or connection loss inside the delete transaction.","commonSituations":"Connection dropped after long neighbor scans; context timeout on a wide neighborhood; backend query failure on the issues table; transaction invalidated by a prior backend error.","solutions":["Inspect the wrapped driver error from GetIssuesByIDsInTx","Retry the delete in a fresh transaction — the delete rolls back atomically, so retry is safe","Raise the context timeout when deleting ids with very large neighborhoods","Check issues-table health/migrations if the failure reproduces on the same ids"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure neighbor hydration will find rows in this repo; cross-repo/external: ids are legitimately skipped\nif err := ctx.Err(); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := store.Delete(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"hydrate neighbors\") {\n    // GetIssuesByIDsInTx failed; storage issue, retry with fresh tx\n}","preventionTips":["Use DryRun to exercise the full read path (including hydration) before committing","Keep context timeouts proportional to neighborhood size","Check issues-table health if failures repeat on the same ids","Remember external:/cross-repo targets hydrating to nothing is normal, not an error"],"tags":["database","hydration","neighbors","wrapper-error"],"backgroundTag":"db-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}