{"record":{"id":"004e448ca03e2928","repo":"gastownhall/beads","slug":"delete-issues-w","errorCode":null,"errorMessage":"delete issues: %w","messagePattern":"delete issues: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/storage/issueops/bulk_ops.go","lineNumber":215,"sourceCode":"\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)\n\t}\n\n\trowsAffected, err := result.RowsAffected()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"rows affected: %w\", err)\n\t}\n\n\t// Journal each deleted issue in the same transaction. issueIDs is the exact\n\t// set removed by the DELETE above (both were scoped to source_repo), so\n\t// there are no phantom records here. The source-repo bulk delete plumbing\n\t// carries no actor, so the rows record none.\n\tfor _, id := range issueIDs {\n\t\tif err := RecordDeleteInTx(ctx, tx, id, \"\"); err != nil {\n\t\t\treturn int(rowsAffected), err\n\t\t}\n\t}\n\n\tif err := RecomputeIsBlockedInTx(ctx, tx, affectedIssues, affectedWisps); err != nil {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/bulk_ops.go#L197-L233","documentation":"The core bulk DELETE (`DELETE FROM issues WHERE source_repo = ?`) failing is wrapped as \"delete issues: %w\". This is the main destructive statement; its failure rolls back nothing by itself (caller's tx governs), but signals the issues rows were not removed.","triggerScenarios":"tx.ExecContext on the DELETE fails: foreign-key constraint from a table still referencing issues (no ON DELETE CASCADE), database locked by a concurrent writer, read-only connection, or context canceled.","commonSituations":"Schema variant lacking CASCADE on dependent tables (e.g. a plugin-added table referencing issues); another bd process mid-write; replica/read-only connection mistakenly used for the delete.","solutions":["Read the wrapped error — a FOREIGN KEY constraint failed means a child table still references the issues","Migrate or add CASCADE handling for any new referencing tables","Retry when the database lock clears; serialize bulk deletes against other writers","Point the operation at a writable primary connection, not a read-only replica"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// detect tables referencing issues without cascade before deleting\nrows, _ := db.Query(\"SELECT name FROM sqlite_master WHERE type='table'\") // inspect schema for FK references","typeGuard":"if strings.Contains(err.Error(), \"FOREIGN KEY constraint failed\") { /* a child table still references issues */ }","tryCatchPattern":"err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo)\nif err != nil {\n    if strings.Contains(err.Error(), \"FOREIGN KEY\") {\n        // migrate schema to add ON DELETE CASCADE for the referencing table\n    }\n    // the tx is aborted: rollback and retry after fixing\n    tx.Rollback()\n    return err\n}","preventionTips":["Roll back the transaction on any bulk-delete error; steps are atomic in intent","Extend migrations (not runtime patches) whenever new tables reference issues","Run bulk deletes against a writable primary, never a read-only replica"],"tags":["database","sql-delete","foreign-key","bulk-delete"],"backgroundTag":"foreign-key-constraint-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}