MemPalace/mempalace · critical · UnsupportedCapabilityError

backend does not support lexical_search

Error message

backend does not support lexical_search

What it means

Raised as RebuildPartialError when a bulk upsert into the destination collection fails mid-way during a palace rebuild: some rows were written (the dest is now a partial palace) and the original was possibly archived. The error carries partial_counts, failed_collection, dest_palace, and archive_path so the operator knows exactly what state each copy is in.

Source

Thrown at mempalace/backends/base.py:544

    def run_maintenance(self, kind: str) -> "MaintenanceResult":
        """Run a maintenance ``kind`` and return an observable result (RFC 001).

        Backends advertise supported kinds in ``BaseBackend.maintenance_kinds``
        and override this. The default supports nothing, so every kind raises
        :class:`UnsupportedMaintenanceKindError`. Implementations MUST serialize
        concurrent same-kind runs and report ``already_running`` rather than
        stacking the work.
        """
        raise UnsupportedMaintenanceKindError(f"backend does not support maintenance kind {kind!r}")

    def lexical_search(
        self,
        *,
        query: str,
        n_results: int = 10,
        where: Optional[dict] = None,
    ) -> LexicalResult:
        raise UnsupportedCapabilityError("backend does not support lexical_search")

    def update(
        self,
        *,
        ids: list[str],
        documents: Optional[list[str]] = None,
        metadatas: Optional[list[dict]] = None,
        embeddings: Optional[list[list[float]]] = None,
    ) -> None:
        """Default non-atomic update: get + merge + upsert.

        Backends advertising ``supports_update`` MUST override with an atomic
        single-round-trip implementation.
        """
        if documents is None and metadatas is None and embeddings is None:
            raise ValueError("update requires at least one of documents, metadatas, embeddings")

        n = len(ids)

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Read the message: if an archive_path is given, the original palace is safe there; if not, the source is unchanged.
  2. Delete the partial destination palace named in the message — it is incomplete and must not be used.
  3. Fix the root cause ({exc!r}: disk space, bad metadata row, chromadb health).
  4. Re-run the rebuild; with an archive, pass --source {archive_path} to rebuild from the archived original.

Example fix

# Recovery flow after RebuildPartialError
shutil.rmtree(dest_palace)            # remove partial copy
cli.main(['rebuild', '--source', archive_path, ...])  # rebuild from archive
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil
free = shutil.disk_usage(dest_root).free
if free < estimated_palace_size * 2:
    raise SystemExit('insufficient disk space for rebuild + archive')

Try / catch

try:
    rebuild(...)
except RebuildPartialError as e:
    shutil.rmtree(e.dest_palace)          # partial copy is unusable
    if e.archive_path:
        rebuild(source=e.archive_path)    # original is safe in archive
    else:
        retry()                            # source was never touched

Prevention

When it happens

Trigger: The upsert loop over extracted rows raises after {upserted} rows succeeded — disk full, embedding dimension mismatch, backend crash, or invalid metadata mid-stream.

Common situations: Rebuilding a large palace onto a nearly-full disk; chromadb rejecting a row with oversized/invalid metadata; the archive step moved the original aside so the user must recover from archive_path.

Related errors


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