gastownhall/beads · error
hydrate labels: %w
Error message
hydrate labels: %w
What it means
Raised inside hydrateIssues when getLabelsFromTable fails fetching label rows for the hydrated issue IDs from the given label table. The error wraps the underlying query/scan failure as "hydrate labels: <err>" and aborts hydration of the result page.
Source
Thrown at internal/storage/domain/db/issue_search.go:337
sortRowsGoSide(ids, func(id string) string { return id }, filter.SortBy, filter.SortDesc)
return finishWindow(ids, window)
}
func (r *issueSQLRepositoryImpl) hydrateIssues(ctx context.Context, issues []*types.Issue, tables filterTables, includeDeps bool, skipLabels bool) error {
if len(issues) == 0 {
return nil
}
ids := make([]string, len(issues))
for i, issue := range issues {
ids[i] = issue.ID
}
if !skipLabels {
labelMap, err := r.getLabelsFromTable(ctx, tables.Labels, ids)
if err != nil {
return fmt.Errorf("hydrate labels: %w", err)
}
for _, issue := range issues {
if labels, ok := labelMap[issue.ID]; ok {
issue.Labels = labels
}
}
}
if includeDeps {
depMap, err := r.getDependencyRecordsFromTable(ctx, tables.Dependencies, ids)
if err != nil {
return fmt.Errorf("hydrate dependencies: %w", err)
}
for _, issue := range issues {
if deps, ok := depMap[issue.ID]; ok {
issue.Dependencies = deps
}
}View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap to distinguish query failure from scan failure.
- Run `bd doctor` / migrations so the labels table exists with the expected columns.
- Repair or remove malformed label rows (NULL issue_id/label).
- Retry after clearing locks from other bd processes; use SkipWisps if wisp side tables are intentionally absent.
Example fix
// before
// wisp_labels table missing -> "no such table: wisp_labels"
page, err := store.Search(ctx, q, types.IssueFilter{Ephemeral: &t})
// after
page, err := store.Search(ctx, q, types.IssueFilter{SkipWisps: true})
// or run migrations: bd doctor / bd migrate Defensive patterns
Strategy: validation
Validate before calling
if err := bd.CheckTables(dbPath, "labels"); err != nil {
return fmt.Errorf("run `bd migrate`: %w", err)
} Type guard
func isLabelHydrateError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "hydrate labels: ")
} Try / catch
page, err := store.Search(ctx, q, filter)
if err != nil && isLabelHydrateError(err) {
if name, ok := dberrors.MissingTableName(err); ok && sqlbuild.OptionalWispTable(name) {
filter.SkipWisps = true // retry issues-plane only
page, err = store.Search(ctx, q, filter)
}
} Prevention
- Keep migrations current so label tables exist.
- Use SkipWisps for databases without the wisp plane.
- Repair NULL issue_id/label rows after external edits.
- Avoid concurrent write locks during search-heavy scripts.
When it happens
Trigger: Batched `SELECT issue_id, label FROM <labels> WHERE issue_id IN (...)` fails: the labels (or wisp_labels) table is missing, the DB is locked, the connection drops, or a label row cannot be scanned (NULL/non-string value).
Common situations: Old database created before the labels table existed; migration skipped; corrupt label rows added by external tooling; concurrent bd write lock stalling reads; wisp searches hitting an absent optional wisp_labels table.
Related errors
- failed to get wisp labels: %w
- descendants: hydrate issues: %w
- descendants: hydrate wisps: %w
- search %s: hydrate: %w
- hydrate dependencies: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b8e43237055ee611.
Report an issue: GitHub.