{"record":{"id":"b675c537d906ecc2","repo":"gastownhall/beads","slug":"resolve-existing-wisps-for-batch-delete-w","errorCode":null,"errorMessage":"resolve existing wisps for batch delete: %w","messagePattern":"resolve existing wisps for batch delete: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/wisps.go","lineNumber":446,"sourceCode":"\t}\n\tdefer func() { _ = tx.Rollback() }()\n\n\tclearJournalScope := s.scopeEventsJournalTransaction(tx)\n\tdefer clearJournalScope()\n\n\taffectedIssues, affectedWisps, aerr := issueops.AffectedByDeletionInTx(ctx, tx, nil, ids)\n\tif aerr != nil {\n\t\treturn 0, fmt.Errorf(\"affected by batched wisp delete: %w\", aerr)\n\t}\n\n\t// Resolve WHICH wisps this batch actually removes before the DELETE runs:\n\t// afterwards they are gone, and RowsAffected reports a count, not a set.\n\t// GC hands this path ids it scanned earlier, so an already-collected wisp is\n\t// a routine case, and a phantom delete record would tell a consumer to drop\n\t// a bead this transaction never touched.\n\tdeletedIDs, err := issueops.ExistingIssueIDsInTableInTx(ctx, tx, \"wisps\", ids)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"resolve existing wisps for batch delete: %w\", err)\n\t}\n\t// Edges are journaled before the rows go, while their source snapshots can\n\t// still be read.\n\tif err := issueops.RecordDependencyRemovalsForIssuesInTx(ctx, tx, deletedIDs); err != nil {\n\t\treturn 0, fmt.Errorf(\"journal dependency removals for batched wisp delete: %w\", err)\n\t}\n\n\tinClause, args := doltBuildSQLInClause(ids)\n\n\t//nolint:gosec // G201: inClause contains only ? markers\n\tresult, err := tx.ExecContext(ctx,\n\t\tfmt.Sprintf(\"DELETE FROM wisps WHERE id IN (%s)\", inClause),\n\t\targs...)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to batch delete wisps: %w\", err)\n\t}\n\trowsAffected, _ := result.RowsAffected()\n","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/wisps.go#L428-L464","documentation":"This error wraps failures from issueops.ExistingIssueIDsInTableInTx, which resolves which of the requested wisp IDs actually exist in the wisps table before the DELETE runs. The transaction must know the real deleted set so delete-journal records are only written for wisps it actually removes (RowsAffected gives a count, not a set). If this lookup fails, the batch aborts and rolls back.","triggerScenarios":"DeleteWisps/GC delete path where the SELECT used by ExistingIssueIDsInTableInTx against the wisps table errors: lost Dolt connection, cancelled context, or a missing/corrupt wisps table.","commonSituations":"Database file locked or server unavailable during GC; running bd against a repo whose schema predates the wisps table; transient network failure between agent and a remote Dolt server.","solutions":["Confirm the wisps table exists and is intact (run the tool's doctor/check or dolt schema inspect); re-run migrations if needed","Retry after restoring Dolt connectivity; already-collected wisps being absent is routine and handled, only the query itself failing raises this","Address the wrapped driver error (timeout, lock, cancelled ctx) reported in the error chain","Ensure the caller's context is not cancelled prematurely (increase timeout, check signal handling)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Go: pre-check reachability; existence of individual IDs is handled internally\nif err := ctx.Err(); err != nil { return err }\nif err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"dolt unreachable: %w\", err) }","typeGuard":null,"tryCatchPattern":"_, err := store.DeleteWisps(ctx, ids)\nif err != nil && strings.Contains(err.Error(), \"resolve existing wisps\") {\n    // transient lookup failure: retry once after backoff\n    time.Sleep(time.Second)\n    _, err = store.DeleteWisps(ctx, ids)\n}\nreturn err","preventionTips":["Retry batch deletes — they are transactional and safe to re-attempt","Ensure the wisps table schema is current (run migrations after upgrades)","Don't pre-filter IDs yourself; the path tolerates already-collected wisps","Avoid running deletes while the Dolt server is restarting or unreachable"],"tags":["dolt","storage","transaction","sql"],"backgroundTag":"wisp-delete-existing-id-lookup-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}