{"record":{"id":"4a2e8df5c129420d","repo":"gastownhall/beads","slug":"affected-by-source-repo-delete-w","errorCode":null,"errorMessage":"affected by source-repo delete: %w","messagePattern":"affected by source-repo delete: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/bulk_ops.go","lineNumber":197,"sourceCode":"\t}\n\tvar issueIDs []string\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\t_ = rows.Close()\n\t\t\treturn 0, fmt.Errorf(\"scan issue ID: %w\", err)\n\t\t}\n\t\tissueIDs = append(issueIDs, id)\n\t}\n\t_ = rows.Close()\n\n\tif len(issueIDs) == 0 {\n\t\treturn 0, nil\n\t}\n\n\taffectedIssues, affectedWisps, aerr := AffectedByDeletionInTx(ctx, tx, issueIDs, nil)\n\tif aerr != nil {\n\t\treturn 0, fmt.Errorf(\"affected by source-repo delete: %w\", aerr)\n\t}\n\n\t// Deleted issues hold no leases: clear them while the id set is still\n\t// joinable (before the issues rows go away).\n\tif _, err := tx.ExecContext(ctx,\n\t\t`DELETE FROM leases WHERE issue_id IN (SELECT id FROM issues WHERE source_repo = ?)`, sourceRepo); err != nil {\n\t\treturn 0, fmt.Errorf(\"delete leases: %w\", err)\n\t}\n\n\t// Edges are journaled before the rows go, while their source snapshots can\n\t// still be read.\n\tif err := RecordDependencyRemovalsForIssuesInTx(ctx, tx, issueIDs); err != nil {\n\t\treturn 0, fmt.Errorf(\"journal dependency removals for source-repo delete: %w\", err)\n\t}\n\n\tresult, err := tx.ExecContext(ctx, `DELETE FROM issues WHERE source_repo = ?`, sourceRepo)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"delete issues: %w\", err)","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/bulk_ops.go#L179-L215","documentation":"Before deleting, the function computes which remaining issues/wisps are affected via AffectedByDeletionInTx; failure is wrapped as \"affected by source-repo delete: %w\". This is an internal dependency-graph query inside the same transaction.","triggerScenarios":"AffectedByDeletionInTx returns an error: its internal queries fail (missing dependency/blocking tables), the transaction is aborted, or the context is canceled while computing the affected set.","commonSituations":"Schema drift (dependencies table missing or renamed); timeout on repos with very large dependency graphs; tx invalidated by an earlier failed statement in the caller's transaction.","solutions":["Check the inner error from AffectedByDeletionInTx for the failing statement","Verify dependencies-related tables exist (schema up to date)","Retry the transaction with a longer context deadline for large graphs","Confirm the tx is healthy; begin a fresh transaction if a prior statement rolled it back"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-check dependency tables exist\n_, err := db.Query(\"SELECT 1 FROM dependencies LIMIT 1\")","typeGuard":"if errors.Is(err, context.Canceled) { /* abort, do not retry */ }","tryCatchPattern":"err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo)\nif isTransientDBErr(err) { // busy/locked\n    time.Sleep(backoff)\n    err = retryWholeTransaction(ctx, repo)\n}","preventionTips":["Schedule bulk deletes during low write contention","Retry the full transaction atomically rather than individual steps","Use exponential backoff for busy/locked driver errors"],"tags":["database","dependency-graph","bulk-delete"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}