MemPalace/mempalace · error · PalaceNotFoundError

{db_path}

Error message

{db_path}

What it means

`PalaceNotFoundError` whose message is just the db file path, raised in `SQLiteExactBackend._connect`. When `create=False`, the backend verifies `palace/<name>.db` exists on disk before connecting; if not, it raises rather than letting sqlite silently create an empty database and mask the missing-palace bug.

Source

Thrown at mempalace/backends/sqlite_exact.py:953

                return
            handle.closed = True
            try:
                handle.conn.close()
            except Exception:
                logger.debug(
                    "Failed to close stale immutable sqlite_exact reader for %s",
                    palace_path,
                    exc_info=True,
                )

    def _connect(self, palace_path: str, create: bool, *, read_only: bool = False):
        if self._closed:
            raise BackendClosedError("SQLiteExactBackend has been closed")
        if create and read_only:
            raise ValueError("sqlite_exact read-only connections cannot create a palace")
        db_path = self._db_path(palace_path)
        if not create and not os.path.isfile(db_path):
            raise PalaceNotFoundError(db_path)
        if create:
            os.makedirs(palace_path, exist_ok=True)
            try:
                os.chmod(palace_path, 0o700)
            except (OSError, NotImplementedError):
                pass
        # Hold the registry lock across cache-check + connect + schema init:
        # two threads first-opening the same palace must not each create a
        # connection (the loser leaked unclosed and outlived close()) nor run
        # _init_schema concurrently on a fresh file, which surfaces transient
        # "database is locked" errors before WAL mode is established. Only
        # first-open pays for the I/O under the lock; cache hits are a dict
        # probe.
        with self._clients_lock:
            if self._closed:
                raise BackendClosedError("SQLiteExactBackend has been closed")
            clients = self._read_only_clients if read_only else self._clients
            cached = clients.get(palace_path)

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Verify the path: `ls <palace_path>` and check the `*.db` file actually exists where you point the backend.
  2. If the palace should be created, pass `create=True` (or run the mining command that builds it).
  3. Use absolute palace paths (or resolve from config) instead of relative paths that shift with cwd.
  4. Catch PalaceNotFoundError and surface an onboarding/setup hint to the user.

Example fix

# before
handle = backend._connect("~/palaces/alice", create=False)  # path typo / not built

# after
palace_path = str(Path.home() / "palaces" / "alice")
if not Path(palace_path, "mempalace.db").is_file():
    raise SystemExit(f"palace not found at {palace_path}; run `mempalace mine` first")
handle = backend._connect(palace_path, create=False)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def palace_db_exists(backend, palace_path) -> bool:
    return Path(backend._db_path(palace_path)).is_file()

Try / catch

try:
    col = backend.get_collection(palace, name)
except PalaceNotFoundError as e:
    raise SystemExit(f"palace db missing at {e}; run `mempalace mine` first or fix the path") from e

Prevention

When it happens

Trigger: Calling any non-create API (get_collection with create=False, delete_collection, a read) against a palace path that has no db file — wrong path, typo in palace name, palace not yet built, or a fresh clone without the data directory.

Common situations: Wrong working directory so the relative palace path resolves elsewhere; first run on a new machine before `mempalace mine` created the palace; renaming/moving the palace directory; CI checkout without the data.

Related errors


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