gastownhall/beads · error
search issues with counts: ephemeral wisp probe: %w
Error message
search issues with counts: ephemeral wisp probe: %w
What it means
SearchIssuesWithCountsInTx wraps a failure of wispsTableEmptyOrMissingInTx when filter.Ephemeral is true. The ephemeral path first probes whether the wisps table is empty or absent before querying it; if that probe query fails (as opposed to reporting empty/missing, which is handled), the search returns this wrapped error.
Source
Thrown at internal/storage/issueops/search_counts.go:22
"context"
"database/sql"
"fmt"
"sort"
"github.com/steveyegge/beads/internal/storage/sqlbuild"
"github.com/steveyegge/beads/internal/types"
)
func SearchIssuesWithCountsInTx(ctx context.Context, tx *sql.Tx, query string, filter types.IssueFilter) ([]*types.IssueWithCounts, error) {
wispDepsExist, err := optionalTableExistsInTx(ctx, tx, "wisp_dependencies")
if err != nil {
return nil, fmt.Errorf("search issues with counts: wisp dependency probe: %w", err)
}
if filter.Ephemeral != nil && *filter.Ephemeral {
empty, probeErr := wispsTableEmptyOrMissingInTx(ctx, tx)
if probeErr != nil {
return nil, fmt.Errorf("search issues with counts: ephemeral wisp probe: %w", probeErr)
}
if !empty && wispDepsExist {
wisps, err := runFilterSearchQueryInTx(ctx, tx, query, filter, WispsFilterTables, true)
if err != nil && !missingOptionalWispTable(err) {
return nil, err
}
if len(wisps) > 0 {
return finishSearchIssuesWithCounts(wisps, filter)
}
}
// Fall through: the wisps tier is missing/empty or matched no rows.
// Mirror SearchIssuesInTx / CountIssuesInTx so count-projection searches
// also surface a durable issues-table row flagged ephemeral=1 instead of
// dropping it. Use the same IssuesFilterTables query the non-ephemeral
// path uses, keeping the GH#4387 count/list cardinality parity for
// searches that project counts (e.g. `bd search --counts --include-infra`).
out, err := runFilterSearchQueryInTx(ctx, tx, query, filter, IssuesFilterTables, wispDepsExist)
if err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap probeErr for the real driver error; fix that root cause
- Check for concurrent writers/locks on the database file
- Retry the search; probe failures are typically transient (locks, connection)
- Raise the context timeout for slow or remote databases
- Verify DB integrity with bd doctor if failures persist
Example fix
// before: ephemeral search against a DB locked by a bulk import filter.Ephemeral = &yes res, err := searchWithCounts(ctx, tx, q, filter) // probe fails on lock // after: wait/retry around the writer, or run after import completes <-importDone res, err := searchWithCounts(ctx, tx, q, filter)
Defensive patterns
Strategy: retry
Validate before calling
// ensure the wisps table is at least introspectable before an ephemeral search
var name string
err := tx.QueryRowContext(ctx,
"SELECT name FROM sqlite_master WHERE type='table' AND name='wisps'").Scan(&name)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("wisps introspection broken: %w", err)
} Type guard
func isEphemeralProbeErr(err error) bool {
return err != nil && strings.Contains(err.Error(),
"search issues with counts: ephemeral wisp probe: ")
} Try / catch
res, err := issueops.SearchIssuesWithCountsInTx(ctx, tx, q, filter)
if err != nil && isEphemeralProbeErr(err) {
time.Sleep(100 * time.Millisecond) // lock contention often clears
res, err = issueops.SearchIssuesWithCountsInTx(ctx, tx, q, filter)
} Prevention
- Schedule ephemeral searches outside bulk-write windows
- Use WAL mode / short write transactions to reduce lock contention
- Retry transient failures with small backoff
- Verify DB integrity periodically with bd doctor
When it happens
Trigger: Calling SearchIssuesWithCountsInTx with filter.Ephemeral = &true where the wisps emptiness probe SQL errors — DB locked, connection dropped, ctx cancelled, or catalog introspection failure.
Common situations: Concurrent writer holding the SQLite write lock; remote Dolt server outage; deadline too short for the probe plus search; corrupted DB.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- search issues with counts: wisp probe: %w
- count open wisp children for %s: %w
- search issues with counts: wisp dependency probe: %w
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9a673901520c3c64.
Report an issue: GitHub.