{"record":{"id":"61cca28faacb5ef3","repo":"gastownhall/beads","slug":"hydrate-dependencies-w","errorCode":null,"errorMessage":"hydrate dependencies: %w","messagePattern":"hydrate dependencies: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue_search.go","lineNumber":349,"sourceCode":"\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}\n\t}\n\n\treturn nil\n}\n\n//nolint:gosec // G201: labelTable is \"labels\" or \"wisp_labels\" (hardcoded by callers).\nfunc (r *issueSQLRepositoryImpl) getLabelsFromTable(ctx context.Context, labelTable string, ids []string) (map[string][]string, error) {\n\tresult := make(map[string][]string)\n\tfor start := 0; start < len(ids); start += queryBatchSize {\n\t\tend := start + queryBatchSize\n\t\tif end > len(ids) {\n\t\t\tend = len(ids)","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue_search.go#L331-L367","documentation":"Raised inside hydrateIssues when getDependencyRecordsFromTable fails fetching dependency records for the hydrated issue IDs, wrapped as \"hydrate dependencies: <err>\". This only runs when the caller sets filter.IncludeDependencies, so it appears on dependency-inclusive searches.","triggerScenarios":"With IncludeDependencies=true, the query against the dependencies (or wisp dependencies) table fails: table missing, locked DB, connection loss, or unscannable dependency rows (NULL issue_id/depends_on).","commonSituations":"Database predating the dependencies table; manually edited dependency rows; Dolt replication conflict leaving NULL foreign keys; lock contention with a concurrent bd mutator.","solutions":["Unwrap the error to identify the failing statement and cause.","Run migrations / `bd doctor` to ensure the dependencies table exists and matches the schema.","Repair rows with NULL or dangling issue_id/depends_on values.","If dependencies are optional for your use case, set filter.IncludeDependencies=false to bypass hydration."],"exampleFix":"// before\nfilter := types.IssueFilter{IncludeDependencies: true} // dependencies table missing\n// after\nbd doctor && bd migrate // create/repair tables\nfilter := types.IssueFilter{IncludeDependencies: true}","handlingStrategy":"fallback","validationCode":"if err := bd.CheckTables(dbPath, \"dependencies\"); err != nil {\n\t// proceed without dependencies rather than failing\n\tfilter.IncludeDependencies = false\n}","typeGuard":"func isDepHydrateError(err error) bool {\n\treturn err != nil && strings.HasPrefix(err.Error(), \"hydrate dependencies: \")\n}","tryCatchPattern":"page, err := store.Search(ctx, q, types.IssueFilter{IncludeDependencies: true})\nif err != nil && isDepHydrateError(err) {\n\t// fall back to dependency-free search\n\tpage, err = store.Search(ctx, q, types.IssueFilter{})\n}","preventionTips":["Only set IncludeDependencies when the schema is migrated to include the dependencies table.","Run `bd doctor` before dependency-aware tooling.","Fix NULL depends_on values promptly; they break hydration scans.","Serialize writes to avoid lock contention during hydration."],"tags":["database","dependencies","hydration","schema"],"backgroundTag":"hydration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}