thedotmack/claude-mem · warning
FTS fallback failed for observations
Error message
FTS fallback failed for observations
What it means
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.
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.
Defensive patterns
Strategy: fallback
Validate before calling
if (!query || query.trim().length === 0) return emptyResponse();
Try / catch
try {
results = sessionSearch.searchObservations(query, options);
} catch (ftsError) {
logger.warn('FTS fallback failed for observations', { ftsError });
results = [];
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: FTS5 table unavailable after migration; database locked or disk issues; special characters in queries breaking tokenization upstream.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- FTS fallback failed for timeline
- ValidationError
- API key prompt cancelled — falling back to Claude provider.
- Chroma query failed
- [claude-mem] Failed to parse search results:
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/3c691fb4539d70f9.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/worker/SearchManager.ts:942
try {
const limit = options.limit || 20;
results = await this.hybridSemanticHydrate(query, 'observation', options.project, options.platformSource, (ids) =>
this.sessionStore.getObservationsByIds(ids, { orderBy: 'relevance', limit, project: options.project, platformSource: options.platformSource })
);
} catch (chromaError) {
const errorObject = chromaError instanceof Error ? chromaError : new Error(String(chromaError));
logger.error('WORKER', 'Chroma search failed for observations, falling back to FTS', {}, errorObject);
}
}
if (results.length === 0) {
try {
const ftsResults = this.sessionSearch.searchObservations(query, options);
if (ftsResults.length > 0) {
results = ftsResults;
}
} catch (ftsError) {
logger.warn('SEARCH', 'FTS fallback failed for observations', {}, ftsError instanceof Error ? ftsError : undefined);
}
}
if (results.length === 0) {
return {
content: [{
type: 'text' as const,
text: `No observations found matching "${query}"`
}]
};
}
const header = `Found ${results.length} observation(s) matching "${query}"\n\n${this.formatter.formatTableHeader()}`;
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
return {
content: [{
type: 'text' as const,View on GitHub (pinned to d8bc9755e7)