{"record":{"id":"3c691fb4539d70f9","repo":"thedotmack/claude-mem","slug":"fts-fallback-failed-for-observations","errorCode":null,"errorMessage":"FTS fallback failed for observations","messagePattern":"FTS fallback failed for observations","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/worker/SearchManager.ts","lineNumber":942,"sourceCode":"      try {\n        const limit = options.limit || 20;\n        results = await this.hybridSemanticHydrate(query, 'observation', options.project, options.platformSource, (ids) =>\n          this.sessionStore.getObservationsByIds(ids, { orderBy: 'relevance', limit, project: options.project, platformSource: options.platformSource })\n        );\n      } catch (chromaError) {\n        const errorObject = chromaError instanceof Error ? chromaError : new Error(String(chromaError));\n        logger.error('WORKER', 'Chroma search failed for observations, falling back to FTS', {}, errorObject);\n      }\n    }\n\n    if (results.length === 0) {\n      try {\n        const ftsResults = this.sessionSearch.searchObservations(query, options);\n        if (ftsResults.length > 0) {\n          results = ftsResults;\n        }\n      } catch (ftsError) {\n        logger.warn('SEARCH', 'FTS fallback failed for observations', {}, ftsError instanceof Error ? ftsError : undefined);\n      }\n    }\n\n    if (results.length === 0) {\n      return {\n        content: [{\n          type: 'text' as const,\n          text: `No observations found matching \"${query}\"`\n        }]\n      };\n    }\n\n    const header = `Found ${results.length} observation(s) matching \"${query}\"\\n\\n${this.formatter.formatTableHeader()}`;\n    const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));\n\n    return {\n      content: [{\n        type: 'text' as const,","sourceCodeStart":924,"sourceCodeEnd":960,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker/SearchManager.ts#L924-L960","documentation":"Same FTS fallback guard as the timeline path, but for the dedicated observations search: when the primary observation search returns nothing, the FTS fallback searchObservations(query, options) throwing is caught and logged, then the handler proceeds with an empty result response.","triggerScenarios":"searchObservations handler's primary path yields zero results and the FTS fallback this.sessionSearch.searchObservations(query, options) throws — e.g. FTS index corruption, malformed query tokens, or DB errors.","commonSituations":"FTS5 table unavailable after migration; database locked or disk issues; special characters in queries breaking tokenization upstream.","solutions":["Read ftsError in the log to identify the SQLite-level cause.","Rebuild the FTS index (rebuild command or INSERT INTO ...('rebuild')).","Confirm the FTS extension is enabled in the bundled SQLite build.","Empty results are still returned gracefully — retry after repairing the index."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if (!query || query.trim().length === 0) return emptyResponse();","typeGuard":null,"tryCatchPattern":"try {\n  results = sessionSearch.searchObservations(query, options);\n} catch (ftsError) {\n  logger.warn('FTS fallback failed for observations', { ftsError });\n  results = [];\n}","preventionTips":["Rebuild the FTS index if searches consistently return empty","Avoid raw FTS operators in user queries unless intended","Monitor the SEARCH logger for repeated fallback failures"],"tags":["search","fts","fallback"],"backgroundTag":"database-query-failed","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}