{"record":{"id":"cc686eec284a1c67","repo":"gastownhall/beads","slug":"query-issues-w","errorCode":null,"errorMessage":"query issues: %w","messagePattern":"query issues: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/bulk_ops.go","lineNumber":178,"sourceCode":"\t\t\t}\n\t\t\tresult[c.IssueID] = append(result[c.IssueID], &c)\n\t\t}\n\t\tif err := rows.Err(); err != nil {\n\t\t\t_ = rows.Close()\n\t\t\treturn err\n\t\t}\n\t\t_ = rows.Close()\n\t}\n\treturn nil\n}\n\n// DeleteIssuesBySourceRepoInTx removes all issues from a source repo and their related data.\n//\n//nolint:gosec // G201: table is validated by hardcoded list\nfunc DeleteIssuesBySourceRepoInTx(ctx context.Context, tx *sql.Tx, sourceRepo string) (int, error) {\n\trows, err := tx.QueryContext(ctx, `SELECT id FROM issues WHERE source_repo = ?`, sourceRepo)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"query issues: %w\", err)\n\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 {","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/bulk_ops.go#L160-L196","documentation":"DeleteIssuesBySourceRepoInTx first SELECTs ids of all issues matching the given source_repo; any driver failure there is wrapped as \"query issues: %w\". This is the entry-point read for a bulk delete by source repository.","triggerScenarios":"tx.QueryContext on `SELECT id FROM issues WHERE source_repo = ?` fails: issues table missing, transaction already aborted, context canceled/deadline exceeded, or database locked/busy.","commonSituations":"Older database without the expected issues schema; long-running delete hitting context timeout; concurrent writer holding the SQLite lock; reusing a tx that a previous error already rolled back.","solutions":["Read the wrapped driver error to identify the root cause (no such table, database is locked, context deadline)","Ensure the schema is migrated to the current version","Retry the whole transaction on transient busy/lock errors; the delete is transactional so partial state is rolled back","Raise the context timeout for repos with very large issue counts"],"exampleFix":"// before: short context on a huge repo\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n// after: generous timeout for bulk delete\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)","handlingStrategy":"try-catch","validationCode":"// confirm connectivity and schema before the bulk op\nif err := db.PingContext(ctx); err != nil { /* fail fast */ }","typeGuard":"if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { /* handle timeout */ }","tryCatchPattern":"n, err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        // retry the entire transaction with a longer timeout\n    }\n    return err\n}","preventionTips":["Use generous timeouts for bulk deletes on large repos","Verify schema version before running bulk operations","Never reuse a transaction after an earlier error"],"tags":["database","sql-query","bulk-delete"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}