openclaw - 💡(How to fix) Fix Telegram plugin-state cache writes rows with `expires_at = NULL`, hits 1000-row hard cap, migrations fail

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…

Doctor in 2026.5.26 reports:

PluginStateStoreError: Plugin state for telegram exceeds the 1000 live row limit.
Failed migrating Telegram forum topic-name cache entry -1003734409696:1230

Root cause: telegram.message-cache namespace writes rows with expires_at = NULL, so the expiry sweep (idx_plugin_state_expiry WHERE expires_at IS NOT NULL) never evicts them. They accumulate until the per-plugin 1000-row cap, then any new write (including the doctor's topic-name-cache migration) fails.

Error Message

PluginStateStoreError: Plugin state for telegram exceeds the 1000 live row limit. Failed migrating Telegram forum topic-name cache entry -1003734409696:1230

Root Cause

Root cause: telegram.message-cache namespace writes rows with expires_at = NULL, so the expiry sweep (idx_plugin_state_expiry WHERE expires_at IS NOT NULL) never evicts them. They accumulate until the per-plugin 1000-row cap, then any new write (including the doctor's topic-name-cache migration) fails.

Fix Action

Fix / Workaround

Impact

  • Doctor migrations on upgrade silently lose data (topic-name-cache entries dropped when cap is hit during the rewrite).
  • Per-plugin 1000-row ceiling reached forever for any Telegram instance with more than ~1000 cached inbound messages.
  • Manual SQLite prune is the only mitigation, and it refills within hours.
  • topic-name-cache.<hash> namespace appears partially populated after the failed migration — only 1 row where the migration source had more.

Code Example

PluginStateStoreError: Plugin state for telegram exceeds the 1000 live row limit.
Failed migrating Telegram forum topic-name cache entry -1003734409696:1230

---

namespace=telegram.message-cache
entry_key=eafd015eb3f678ca29b14de8:default:-1003734409696:17179
value_json={"sourceMessage":{"message_id":17179, ...}}
created_at=1779886069586
expires_at=NULL
RAW_BUFFERClick to expand / collapse

Summary

Doctor in 2026.5.26 reports:

PluginStateStoreError: Plugin state for telegram exceeds the 1000 live row limit.
Failed migrating Telegram forum topic-name cache entry -1003734409696:1230

Root cause: telegram.message-cache namespace writes rows with expires_at = NULL, so the expiry sweep (idx_plugin_state_expiry WHERE expires_at IS NOT NULL) never evicts them. They accumulate until the per-plugin 1000-row cap, then any new write (including the doctor's topic-name-cache migration) fails.

Evidence

~/.openclaw/plugin-state/state.sqlite, current live state:

namespacerow countrows with expires_at = NULL
telegram.message-cache700700 (100%)
telegram.bot-info-cache10
telegram.topic-name-cache.<hash>11

Within hours of a manual prune this morning the cache refilled to 998/1000.

Sample row:

namespace=telegram.message-cache
entry_key=eafd015eb3f678ca29b14de8:default:-1003734409696:17179
value_json={"sourceMessage":{"message_id":17179, ...}}
created_at=1779886069586
expires_at=NULL

Environment

  • openclaw 2026.5.26 (10ad3aa)
  • node 26.0.0 (homebrew)
  • macOS 25.5.0

Impact

  • Doctor migrations on upgrade silently lose data (topic-name-cache entries dropped when cap is hit during the rewrite).
  • Per-plugin 1000-row ceiling reached forever for any Telegram instance with more than ~1000 cached inbound messages.
  • Manual SQLite prune is the only mitigation, and it refills within hours.
  • topic-name-cache.<hash> namespace appears partially populated after the failed migration — only 1 row where the migration source had more.

Suggested fix direction

Either:

  • Set a TTL on telegram.message-cache writes (e.g. 24h / 7d, matching how long inbound message context is realistically useful), and let pruneExpiredPluginState evict them, OR
  • Cap telegram.message-cache namespace size explicitly with LRU eviction on insert, decoupled from the global 1000-row plugin cap, OR
  • Raise the 1000-row cap (less ideal — same growth pattern will hit any new ceiling).

Side note

Filed alongside #87331 (Native hook relay unavailable regression). Both surfaced on the same upgrade; this one looks design-level rather than a regression.

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 Telegram plugin-state cache writes rows with `expires_at = NULL`, hits 1000-row hard cap, migrations fail