{"record":{"id":"b8e43237055ee611","repo":"gastownhall/beads","slug":"hydrate-labels-w","errorCode":null,"errorMessage":"hydrate labels: %w","messagePattern":"hydrate labels: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue_search.go","lineNumber":337,"sourceCode":"\n\tsortRowsGoSide(ids, func(id string) string { return id }, filter.SortBy, filter.SortDesc)\n\treturn finishWindow(ids, window)\n}\n\nfunc (r *issueSQLRepositoryImpl) hydrateIssues(ctx context.Context, issues []*types.Issue, tables filterTables, includeDeps bool, skipLabels bool) error {\n\tif len(issues) == 0 {\n\t\treturn nil\n\t}\n\n\tids := make([]string, len(issues))\n\tfor i, issue := range issues {\n\t\tids[i] = issue.ID\n\t}\n\n\tif !skipLabels {\n\t\tlabelMap, err := r.getLabelsFromTable(ctx, tables.Labels, ids)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"hydrate labels: %w\", err)\n\t\t}\n\t\tfor _, issue := range issues {\n\t\t\tif labels, ok := labelMap[issue.ID]; ok {\n\t\t\t\tissue.Labels = labels\n\t\t\t}\n\t\t}\n\t}\n\n\tif includeDeps {\n\t\tdepMap, err := r.getDependencyRecordsFromTable(ctx, tables.Dependencies, ids)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"hydrate dependencies: %w\", err)\n\t\t}\n\t\tfor _, issue := range issues {\n\t\t\tif deps, ok := depMap[issue.ID]; ok {\n\t\t\t\tissue.Dependencies = deps\n\t\t\t}\n\t\t}","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue_search.go#L319-L355","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n// wisp_labels table missing -> \"no such table: wisp_labels\"\npage, err := store.Search(ctx, q, types.IssueFilter{Ephemeral: &t})\n// after\npage, err := store.Search(ctx, q, types.IssueFilter{SkipWisps: true})\n// or run migrations: bd doctor / bd migrate","handlingStrategy":"validation","validationCode":"if err := bd.CheckTables(dbPath, \"labels\"); err != nil {\n\treturn fmt.Errorf(\"run `bd migrate`: %w\", err)\n}","typeGuard":"func isLabelHydrateError(err error) bool {\n\treturn err != nil && strings.HasPrefix(err.Error(), \"hydrate labels: \")\n}","tryCatchPattern":"page, err := store.Search(ctx, q, filter)\nif err != nil && isLabelHydrateError(err) {\n\tif name, ok := dberrors.MissingTableName(err); ok && sqlbuild.OptionalWispTable(name) {\n\t\tfilter.SkipWisps = true // retry issues-plane only\n\t\tpage, err = store.Search(ctx, q, filter)\n\t}\n}","preventionTips":["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."],"tags":["database","labels","hydration","schema"],"backgroundTag":"hydration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}