thedotmack/claude-mem · warning

FTS5 not available — user_prompts_fts skipped (search uses C

Error message

FTS5 not available — user_prompts_fts skipped (search uses ChromaDB)

What it means

Schema migration v10 creates the `user_prompts` table plus an FTS5 virtual table (`user_prompts_fts`) and sync triggers. If the SQLite build lacks FTS5, the CREATE VIRTUAL TABLE throws; the store commits the base table anyway, records schema version 10 as applied, and warns that prompt search falls back to ChromaDB.

Source

Thrown at src/services/sqlite/SessionStore.ts:1325

        VALUES('delete', old.id, old.prompt_text);
      END;

      CREATE TRIGGER user_prompts_au AFTER UPDATE ON user_prompts BEGIN
        INSERT INTO user_prompts_fts(user_prompts_fts, rowid, prompt_text)
        VALUES('delete', old.id, old.prompt_text);
        INSERT INTO user_prompts_fts(rowid, prompt_text)
        VALUES (new.id, new.prompt_text);
      END;
    `;

    try {
      this.db.run(ftsCreateSQL);
      this.db.run(ftsTriggersSQL);
    } catch (ftsError) {
      if (ftsError instanceof Error) {
        logger.warn('DB', 'FTS5 not available — user_prompts_fts skipped (search uses ChromaDB)', {}, ftsError);
      } else {
        logger.warn('DB', 'FTS5 not available — user_prompts_fts skipped (search uses ChromaDB)', {}, new Error(String(ftsError)));
      }
      this.db.run('COMMIT');
      this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
      logger.debug('DB', 'Created user_prompts table (without FTS5)');
      return;
    }

    this.db.run('COMMIT');

    this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());

    logger.debug('DB', 'Successfully created user_prompts table');
  }

  private ensureDiscoveryTokensColumn(): void {
    const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(11) as SchemaVersion | undefined;
    if (applied) return;

View on GitHub (pinned to 8bc631a71a)

Solutions

  1. Accept the fallback — ChromaDB covers prompt search.
  2. Switch to a runtime whose SQLite has FTS5 (stock Node's node:sqlite does) and recreate the store.
  3. Verify capability with `SELECT * FROM pragma_compile_options() WHERE compile_options LIKE '%FTS5%'`.

Example fix

// before
// CREATE VIRTUAL TABLE ... USING fts5(...) throws on an FTS5-less SQLite
// after
const fts5 = db.prepare("SELECT 1 FROM pragma_compile_options() WHERE compile_options LIKE '%ENABLE_FTS5%'").get();
if (fts5) {
  db.run(ftsCreateSQL);
  db.run(ftsTriggersSQL);
} else {
  // skip FTS; ChromaDB handles search
}
Defensive patterns

Strategy: fallback

Validate before calling

const fts5Available = !!db.prepare("SELECT 1 FROM pragma_compile_options() WHERE compile_options LIKE '%ENABLE_FTS5%'").get();

Try / catch

try {
  db.run(ftsCreateSQL);
  db.run(ftsTriggersSQL);
} catch (ftsError) {
  // degrade gracefully: keep the base table, rely on ChromaDB for search
  logger.warn('DB', 'FTS5 not available — search falls back to ChromaDB', {}, ftsError);
}

Prevention

When it happens

Trigger: `db.run(ftsCreateSQL)` throws because the linked SQLite was compiled without ENABLE_FTS5 (or with SQLITE_OMIT_FTS5).

Common situations: Non-standard Node builds, distro-patched SQLite without FTS5, or embedded runtimes shipping a minimal SQLite.

Related errors


AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20). Data as JSON: /api/errors/2a19f244a7bd3c4e. Report an issue: GitHub.