{"record":{"id":"95b7cf0ca7c306c6","repo":"gastownhall/beads","slug":"search-s-id-scan-scan-w","errorCode":null,"errorMessage":"search %s (id scan): scan: %w","messagePattern":"search (.+?) \\(id scan\\): scan: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue_search.go","lineNumber":312,"sourceCode":"\nfunc (r *issueSQLRepositoryImpl) scanFilterIDs(ctx context.Context, selectKw, fromSQL, whereSQL string, args []any, filter types.IssueFilter, tables filterTables) ([]string, bool, error) {\n\torderBy := orderBySQL(filter.SortBy, filter.SortDesc, tables.Main)\n\twindow := searchWindowForFilter(filter)\n\t//nolint:gosec // G201: SQL fragments from fixed table names and parameterized filters.\n\tidQuery := fmt.Sprintf(`%s%s.id FROM %s %s %s %s`,\n\t\tselectKw, tables.Main, fromSQL, whereSQL, orderBy, window.sql)\n\n\trows, err := r.runner.QueryContext(ctx, idQuery, args...)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"search %s (id scan): %w\", tables.Main, err)\n\t}\n\tdefer func() { _ = rows.Close() }()\n\n\tvar ids []string\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\treturn nil, false, fmt.Errorf(\"search %s (id scan): scan: %w\", tables.Main, err)\n\t\t}\n\t\tids = append(ids, id)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"search %s (id scan): rows: %w\", tables.Main, err)\n\t}\n\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 {","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue_search.go#L294-L330","documentation":"Raised when rows.Scan fails while reading a single id string column during scanFilterIDs. Because the query selects exactly one column into one string, failures usually mean a NULL id (schema corruption) or a driver conversion problem rather than column-count mismatch.","triggerScenarios":"The id-only query returns a row whose id column is NULL or non-text — typically from external edits, partial writes, or replication conflicts in Dolt that left a row without a primary id value.","commonSituations":"Manual SQL edits to the .beads database; a failed/crashed write leaving a partially inserted row; Dolt merge conflicts introducing NULL primary keys.","solutions":["Find the row with the NULL/malformed id: SELECT * FROM issues WHERE id IS NULL.","Repair or delete the corrupt row(s); restore from Dolt history if writes were conflicting.","Run `bd doctor` for integrity validation after repair.","Restore the database from backup if corruption is widespread."],"exampleFix":"// before\n// issues table contains a row with NULL id -> scan into string fails\n// after\nDELETE FROM issues WHERE id IS NULL; -- or restore from dolt history","handlingStrategy":"validation","validationCode":"// integrity check for NULL primary ids before search-heavy workflows\nrows := query(\"SELECT COUNT(*) FROM issues WHERE id IS NULL OR id = ''\")\nif count > 0 { run bd doctor / restore from dolt history }","typeGuard":"func isIDScanTypeError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"(id scan): scan: \")\n}","tryCatchPattern":"page, err := store.Search(ctx, q, filter)\nif err != nil && isIDScanTypeError(err) {\n\treturn fmt.Errorf(\"corrupt issue rows (NULL id); restore from history or `bd doctor`: %w\", err)\n}","preventionTips":["Never mutate primary keys with external SQL tools.","Resolve Dolt merge conflicts before operating on the database.","Schedule periodic `bd doctor` integrity checks.","Back up .beads before risky bulk operations."],"tags":["database","sql","scan","data-corruption"],"backgroundTag":"sql-scan-type-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}