thedotmack/claude-mem · warning
FTS fallback failed for timeline
Error message
FTS fallback failed for timeline
What it means
Logged when the FTS (full-text search) fallback used to backfill timeline results throws. The primary timeline search returned no results, and the fallback call to sessionSearch.searchObservations failed; the failure is swallowed and the flow continues to the empty-results branch.
Solutions
- Check the ftsError detail in the log payload to find the underlying SQLite/FTS failure.
- Rebuild the FTS index for the sessions database.
- Verify database file integrity and that no other process holds a write lock.
- The tool still returns a valid empty-results response — treat this as degraded search, not data loss.
Example fix
// after migration
INSERT INTO observations(observations) VALUES('rebuild'); Defensive patterns
Strategy: fallback
Validate before calling
// verify FTS index health before searching
const ok = db.prepare("SELECT count(*) FROM observations WHERE observations MATCH 'test'").get(); Try / catch
try {
results = sessionSearch.searchObservations(query, opts);
} catch (e) {
logger.warn('FTS fallback failed', { error: e });
results = []; // degrade gracefully to empty results
} Prevention
- Run FTS index rebuilds after schema migrations
- Check SQLite FTS5 extension availability in your build
- Treat empty search results plus this warning as an index-health signal
When it happens
Trigger: searchTimeline's primary search yields nothing, then the fallback this.sessionSearch.searchObservations(query, {project, platformSource, limit:1}) throws (e.g. corrupt/missing FTS index, SQL error).
Common situations: SQLite FTS table missing or corrupted after upgrade/migration; database locked by another process; query syntax issues escaping the FTS layer.
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 observations
- 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/3ef392b55754101b.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/worker/SearchManager.ts:798
if (this.chromaSync) {
logger.debug('SEARCH', 'Using hybrid semantic search for timeline query', {});
try {
results = await this.searchChromaForTimeline(query, project, platformSource);
} catch (chromaError) {
const errorObject = chromaError instanceof Error ? chromaError : new Error(String(chromaError));
logger.error('WORKER', 'Chroma search failed for timeline, continuing without semantic results', {}, errorObject);
}
}
if (results.length === 0) {
try {
const ftsResults = this.sessionSearch.searchObservations(query, { project, platformSource, limit: 1 });
if (ftsResults.length > 0) {
results = ftsResults;
}
} catch (ftsError) {
logger.warn('SEARCH', 'FTS fallback failed for timeline', {}, ftsError instanceof Error ? ftsError : undefined);
}
}
if (results.length === 0) {
return {
content: [{
type: 'text' as const,
text: `No observations found matching "${query}". Try a different search query.`
}]
};
}
const topResult = results[0];
anchorId = topResult.id;
anchorEpoch = topResult.created_at_epoch;
logger.debug('SEARCH', 'Query mode: Using observation as timeline anchor', { observationId: topResult.id });
timelineData = this.sessionStore.getTimelineAroundObservation(topResult.id, topResult.created_at_epoch, depthBefore, depthAfter, project, platformSource);
}View on GitHub (pinned to d8bc9755e7)