{"record":{"id":"8af6c58a81e18005","repo":"MemPalace/mempalace","slug":"daemon-is-not-running-8af6c5","errorCode":null,"errorMessage":"daemon is not running","messagePattern":"daemon is not running","errorType":"exception","errorClass":"DaemonError","httpStatus":null,"severity":"warning","filePath":"mempalace/daemon.py","lineNumber":1380,"sourceCode":"                pass\n        raise\n    finally:\n        if lock_fh is not None:\n            try:\n                lock_fh.close()\n            except Exception:  # noqa: BLE001 - cleanup best-effort\n                pass\n\n\ndef ensure_client(\n    palace_path: str, *, backend: str | None = None, auto_start: bool = True\n) -> DaemonClient:\n    palace_path = canonical_palace_path(palace_path)\n    client = get_client_if_running(palace_path)\n    if client is not None:\n        return client\n    if not auto_start:\n        raise DaemonError(\"daemon is not running\")\n    return start_daemon(palace_path, backend=backend)\n\n\ndef submit_job(\n    kind: str,\n    payload: dict[str, Any],\n    *,\n    palace_path: str | None = None,\n    backend: str | None = None,\n    dedupe_key: str | None = None,\n    priority: int = 0,\n    wait: bool = True,\n    auto_start: bool = False,\n    timeout: float = DEFAULT_WAIT_TIMEOUT,\n    stop_on_lock_deferral: bool = False,\n) -> dict[str, Any]:\n    # Strictly opt-in: callers that want the daemon auto-started must say so\n    # explicitly (the CLI --daemon path passes auto_start=True). The default","sourceCodeStart":1362,"sourceCodeEnd":1398,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/daemon.py#L1362-L1398","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Start the daemon first (start_daemon or ensure_client with auto_start=True), then retry.","If spawning is intentionally forbidden, catch DaemonError and take the documented fallback (direct write path) rather than retrying.","Check why a daemon you expected to be running is not: pid file, endpoint.json, daemon log."],"exampleFix":"# before\nclient = ensure_client(palace_path, auto_start=False)  # raises\n\n# after\nclient = get_client_if_running(palace_path)\nif client is None:\n    client = ensure_client(palace_path, auto_start=True)","handlingStrategy":"fallback","validationCode":"from mempalace.daemon import get_client_if_running\n\nclient = get_client_if_running(palace_path)  # None, never raises, when not running","typeGuard":null,"tryCatchPattern":"from mempalace.daemon import DaemonError\n\ntry:\n    client = ensure_client(palace_path, auto_start=False)\nexcept DaemonError:\n    client = None  # take the direct-write / no-daemon path by design","preventionTips":["When auto_start=False, always pair the call with a None/DaemonError fallback path.","Use get_client_if_running for opportunistic daemon usage.","Don't retry auto_start=False calls in a loop — the daemon won't appear on its own."],"tags":["daemon","client","startup","availability"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}