gastownhall/beads · error
search wisps (ephemeral filter): %w
Error message
search wisps (ephemeral filter): %w
What it means
searchAcrossIssuesAndWisps wraps a failure from searchTable against the wisps table when the caller set filter.Ephemeral=true. When Ephemeral is set, only the wisps table is searched first; an error that missingOptionalWispTable does not classify as a legitimately-absent optional wisp table (e.g. connection failure, a missing non-optional table like the search FROM's lease join) is wrapped and returned instead of being treated as "no wisps".
Source
Thrown at internal/storage/domain/db/issue_search.go:43
issuesFilterTables = sqlbuild.IssuesFilterTables
wispsFilterTables = sqlbuild.WispsFilterTables
)
// missingOptionalWispTable reports whether err is the absence of a wisp-plane
// table a database may legitimately not have. A wisp search touches more than
// that: its FROM clause carries sqlbuild.LeaseJoin and its hydration reads
// wisp_labels, so a blanket table-not-exist check reports a broken database as
// an empty wisp plane and silently drops live rows from the result.
func missingOptionalWispTable(err error) bool {
name, ok := dberrors.MissingTableName(err)
return ok && sqlbuild.OptionalWispTable(name)
}
func (r *issueSQLRepositoryImpl) searchAcrossIssuesAndWisps(ctx context.Context, query string, filter types.IssueFilter) (domain.SearchPage, error) {
if filter.Ephemeral != nil && *filter.Ephemeral {
page, err := r.searchTable(ctx, query, filter, wispsFilterTables)
if err != nil && !missingOptionalWispTable(err) {
return domain.SearchPage{}, fmt.Errorf("search wisps (ephemeral filter): %w", err)
}
if len(page.Items) > 0 {
return page, nil
}
}
if filter.SkipWisps {
page, err := r.searchTable(ctx, query, filter, issuesFilterTables)
if err != nil {
return domain.SearchPage{}, fmt.Errorf("search issues: %w", err)
}
return page, nil
}
empty, probeErr := r.wispsTableEmptyOrMissing(ctx)
if probeErr != nil {
return domain.SearchPage{}, fmt.Errorf("search wisps (merge): probe: %w", probeErr)
}View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped inner error and dberrors.MissingTableName to see exactly which table or failure is involved
- Run bd doctor to verify wisp-plane tables (wisps, wisp_labels) and the leases table exist
- Retry if the inner error is a transient connection failure
- Drop Ephemeral=true and search both planes normally if you do not strictly need ephemeral-only results
Example fix
// before
page, err := store.Search(ctx, q, types.IssueFilter{Ephemeral: &trueVal})
// after: search both planes unless ephemeral-only is a hard requirement
page, err := store.Search(ctx, q, types.IssueFilter{}) Defensive patterns
Strategy: type-guard
Type guard
// mirror the library's own classification
func isOptionalWispTableMissing(err error) bool {
name, ok := dberrors.MissingTableName(err)
return ok && sqlbuild.OptionalWispTable(name)
} Try / catch
page, err := store.Search(ctx, q, types.IssueFilter{Ephemeral: &t})
if err != nil && strings.Contains(err.Error(), "search wisps (ephemeral filter)") {
if !isOptionalWispTableMissing(errors.Unwrap(err)) {
// real breakage: repair or fall back to a full search
page, err = store.Search(ctx, q, types.IssueFilter{})
}
} Prevention
- Only set Ephemeral=true when the wisp plane is known healthy
- Check schema consistency (wisps + wisp_labels + leases) after clone/restore
- Classify errors with dberrors.MissingTableName instead of string matching
- Fall back to a full two-plane search when the ephemeral-only path fails
When it happens
Trigger: Calling SearchAcrossIssuesAndWisps (bd query/search) with Ephemeral=true when the wisps search fails on something other than a missing optional table: broken connection, missing leases table used in the FROM join, engine error, or a genuinely broken wisp schema.
Common situations: Ephemeral-only search during a Dolt outage; a database where wisps exists but wisp_labels (needed for hydration) is missing — the code's own comment warns a blanket table-not-exist tolerance would mask this as an empty result, so real breakage surfaces here.
Related errors
- db: DependencySQLRepository.CycleThroughEdges (wisps): %w
- db: DependencySQLRepository.WispSourceIDs: %w
- db: DependencySQLRepository.GetWispDependencyRecordsForIDs:
- descendants: wisps filter: %w
- descendants: hydrate wisps: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/03f924fab5327af7.
Report an issue: GitHub.