MemPalace/mempalace · warning · UnsupportedMaintenanceKindError

sqlite_exact does not support maintenance kind {kind!r}

Error message

sqlite_exact does not support maintenance kind {kind!r}

What it means

Raised by `SQLiteExactBackend.run_maintenance(kind)` when `kind` is not in `SQLiteExactBackend.maintenance_kinds`. The backend implements only specific maintenance operations (`analyze` for planner stats, `compact` mapping to VACUUM); anything else — e.g. `reindex`, `vacuum-full`, `purge` — is rejected with this error rather than silently ignored.

Source

Thrown at mempalace/backends/sqlite_exact.py:830

        except Exception:
            rows = 0
        # vector_index is null by design — exact cosine over every row, no ANN.
        state = {"row_count": rows, "vector_index": None}
        try:
            with self._cursor() as cur:
                page_count = cur.execute("PRAGMA page_count").fetchone()
                freelist = cur.execute("PRAGMA freelist_count").fetchone()
            state["page_count"] = int(page_count[0]) if page_count else 0
            state["freelist_pages"] = int(freelist[0]) if freelist else 0
        except Exception:
            pass
        return state

    def run_maintenance(self, kind: str):
        from .base import MaintenanceResult, UnsupportedMaintenanceKindError

        if kind not in SQLiteExactBackend.maintenance_kinds:
            raise UnsupportedMaintenanceKindError(
                f"sqlite_exact does not support maintenance kind {kind!r}"
            )
        if kind == "analyze":
            # Refresh planner stats. Concurrent runs serialize on the handle lock.
            with self._cursor(write=True) as cur:
                cur.execute("ANALYZE")
            return MaintenanceResult(kind="analyze", status="ran")

        # compact → VACUUM. It cannot run inside a transaction, so flip the
        # connection to autocommit for the duration. _write_lock takes the
        # handle mutex before the palace lease so a waiting thread cannot
        # retain stale process-reentrant ownership after another thread exits.
        before = self.maintenance_state()
        with self._write_lock():
            conn = self._handle.conn
            prev_isolation = conn.isolation_level
            try:
                conn.commit()

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Inspect `SQLiteExactBackend.maintenance_kinds` and call only those (typically `"analyze"` and `"compact"`).
  2. Guard generic maintenance loops: `if kind in backend.maintenance_kinds: backend.run_maintenance(kind)`.
  3. Catch UnsupportedMaintenanceKindError and skip that kind for this backend instead of failing the whole job.

Example fix

# before
backend.run_maintenance("reindex")  # unsupported

# after
if "reindex" in backend.maintenance_kinds:
    backend.run_maintenance("reindex")
else:
    backend.run_maintenance("analyze")
Defensive patterns

Strategy: try-catch

Validate before calling

def supported_maintenance(backend, kind) -> bool:
    return kind in getattr(backend, "maintenance_kinds", set())

Try / catch

from mempalace.backends.base import UnsupportedMaintenanceKindError

for kind in jobs:
    try:
        backend.run_maintenance(kind)
    except UnsupportedMaintenanceKindError:
        logger.info("skipping %s on %s", kind, type(backend).__name__)

Prevention

When it happens

Trigger: Calling `backend.run_maintenance("reindex")` or any string not in the class-level `maintenance_kinds` set; passing a maintenance kind supported by the ChromaDB backend to sqlite_exact; typos like `"analize"` or `"compact-full"`.

Common situations: Generic maintenance tooling that probes several kinds across backends; config files listing maintenance jobs written for another backend; scripts copied from ChromaDB-based setups.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/d2f7edac41342c34. Report an issue: GitHub.