MemPalace/mempalace · warning · DaemonError

daemon is not running

Error message

daemon is not running

What it means

DaemonError from ensure_client (mempalace/daemon.py:1380): no running daemon was found (get_client_if_running returned None) and the caller passed auto_start=False, so startup is explicitly disallowed. This is the deliberate 'daemon must already be up' contract for callers that never want to spawn a process (e.g. read-only or ephemeral contexts).

Source

Thrown at mempalace/daemon.py:1380

                pass
        raise
    finally:
        if lock_fh is not None:
            try:
                lock_fh.close()
            except Exception:  # noqa: BLE001 - cleanup best-effort
                pass


def ensure_client(
    palace_path: str, *, backend: str | None = None, auto_start: bool = True
) -> DaemonClient:
    palace_path = canonical_palace_path(palace_path)
    client = get_client_if_running(palace_path)
    if client is not None:
        return client
    if not auto_start:
        raise DaemonError("daemon is not running")
    return start_daemon(palace_path, backend=backend)


def submit_job(
    kind: str,
    payload: dict[str, Any],
    *,
    palace_path: str | None = None,
    backend: str | None = None,
    dedupe_key: str | None = None,
    priority: int = 0,
    wait: bool = True,
    auto_start: bool = False,
    timeout: float = DEFAULT_WAIT_TIMEOUT,
    stop_on_lock_deferral: bool = False,
) -> dict[str, Any]:
    # Strictly opt-in: callers that want the daemon auto-started must say so
    # explicitly (the CLI --daemon path passes auto_start=True). The default

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Start the daemon first (start_daemon or ensure_client with auto_start=True), then retry.
  2. If spawning is intentionally forbidden, catch DaemonError and take the documented fallback (direct write path) rather than retrying.
  3. Check why a daemon you expected to be running is not: pid file, endpoint.json, daemon log.

Example fix

# before
client = ensure_client(palace_path, auto_start=False)  # raises

# after
client = get_client_if_running(palace_path)
if client is None:
    client = ensure_client(palace_path, auto_start=True)
Defensive patterns

Strategy: fallback

Validate before calling

from mempalace.daemon import get_client_if_running

client = get_client_if_running(palace_path)  # None, never raises, when not running

Try / catch

from mempalace.daemon import DaemonError

try:
    client = ensure_client(palace_path, auto_start=False)
except DaemonError:
    client = None  # take the direct-write / no-daemon path by design

Prevention

When it happens

Trigger: Calling ensure_client(palace_path, auto_start=False) before any daemon exists; the daemon died between discovery and this call leaving no live endpoint; hook runs in an environment where spawning is forbidden.

Common situations: Read-only tools that opportunistically use the daemon when present; hooks configured to fall back to direct writes instead of starting a daemon; sandboxes that block subprocess spawning.

Related errors


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