openclaw - 💡(How to fix) Fix LCM: FTS index grows unbounded — compaction deletes messages but never cleans FTS entries [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#59994Fetched 2026-04-08 02:37:49
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

Root Cause

In the compaction code path, when old messages are summarized and the originals are deleted from messages, no corresponding DELETE is issued against the messages_fts table. FTS5 does not cascade deletes from external tables — it requires explicit delete commands:

INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', <rowid>, <original_content>);

Or alternatively, the FTS table could be defined with content=messages (external content mode) so it stays in sync automatically.

Fix Action

Workaround

Drop and recreate the FTS tables, then repopulate from current messages:

DROP TABLE IF EXISTS messages_fts;
CREATE VIRTUAL TABLE messages_fts USING fts5(content, tokenize='porter unicode61');
INSERT INTO messages_fts(rowid, content) SELECT message_id, content FROM messages;
VACUUM;

This reduced our database from 618MB to 88MB.

Code Example

INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', <rowid>, <original_content>);

---

-- Check for orphaned FTS entries
SELECT COUNT(*) FROM messages_fts_content 
WHERE id NOT IN (SELECT message_id FROM messages);

-- Compare actual vs FTS row counts
SELECT 
  (SELECT COUNT(*) FROM messages) as actual_messages,
  (SELECT COUNT(*) FROM messages_fts_content) as fts_rows;

---

DROP TABLE IF EXISTS messages_fts;
CREATE VIRTUAL TABLE messages_fts USING fts5(content, tokenize='porter unicode61');
INSERT INTO messages_fts(rowid, content) SELECT message_id, content FROM messages;
VACUUM;
RAW_BUFFERClick to expand / collapse

Bug Description

LCM's message compaction removes rows from the messages table but never deletes the corresponding entries from the messages_fts FTS5 virtual table. Over time this causes the FTS index to grow far larger than the actual message count.

Impact

  • Database bloat: Our LCM database grew to 618MB with 501,681 FTS content rows for only 22,732 actual messages (22:1 ratio)
  • Memory pressure: The gateway process grew to 2.2GB RSS, likely due to loading the bloated FTS index into memory
  • Performance degradation: Response latency increased noticeably as the database grew

Root Cause

In the compaction code path, when old messages are summarized and the originals are deleted from messages, no corresponding DELETE is issued against the messages_fts table. FTS5 does not cascade deletes from external tables — it requires explicit delete commands:

INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', <rowid>, <original_content>);

Or alternatively, the FTS table could be defined with content=messages (external content mode) so it stays in sync automatically.

Reproduction

-- Check for orphaned FTS entries
SELECT COUNT(*) FROM messages_fts_content 
WHERE id NOT IN (SELECT message_id FROM messages);

-- Compare actual vs FTS row counts
SELECT 
  (SELECT COUNT(*) FROM messages) as actual_messages,
  (SELECT COUNT(*) FROM messages_fts_content) as fts_rows;

Workaround

Drop and recreate the FTS tables, then repopulate from current messages:

DROP TABLE IF EXISTS messages_fts;
CREATE VIRTUAL TABLE messages_fts USING fts5(content, tokenize='porter unicode61');
INSERT INTO messages_fts(rowid, content) SELECT message_id, content FROM messages;
VACUUM;

This reduced our database from 618MB to 88MB.

Suggested Fix

Add FTS cleanup to the compaction transaction — when messages are deleted during compaction, also delete their FTS entries in the same transaction. Alternatively, switch to FTS5 external content mode (content=messages) which handles this automatically.

Environment

  • OpenClaw running on Ubuntu 22.04 VPS (8GB RAM)
  • ~22K messages across ~3,300 conversations
  • LCM enabled with compaction threshold 0.6

extent analysis

TL;DR

To fix the database bloat issue, add FTS cleanup to the compaction transaction or switch to FTS5 external content mode.

Guidance

  • Identify the current compaction code path and modify it to include a DELETE statement against the messages_fts table when old messages are deleted from the messages table.
  • Consider switching to FTS5 external content mode by defining the FTS table with content=messages to automatically keep the FTS index in sync with the messages table.
  • Use the provided SQL queries to verify the presence of orphaned FTS entries and compare actual vs FTS row counts.
  • As a temporary workaround, drop and recreate the FTS tables, then repopulate from current messages using the provided SQL script.

Example

INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', <rowid>, <original_content>);

This SQL statement can be used to delete corresponding FTS entries when messages are deleted from the messages table.

Notes

The suggested fix assumes that the compaction code path can be modified to include FTS cleanup. If this is not possible, switching to FTS5 external content mode may be a viable alternative.

Recommendation

Apply workaround: Drop and recreate the FTS tables, then repopulate from current messages, as this provides a temporary solution to reduce database bloat and improve performance.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix LCM: FTS index grows unbounded — compaction deletes messages but never cleans FTS entries [1 participants]