{"record":{"id":"3a67f376a8b922ac","repo":"MemPalace/mempalace","slug":"daemon-exited-during-startup-with-code-proc-retur","errorCode":null,"errorMessage":"daemon exited during startup with code {proc.returncode}","messagePattern":"daemon exited during startup with code (.+?)","errorType":"exception","errorClass":"DaemonError","httpStatus":null,"severity":"critical","filePath":"mempalace/daemon.py","lineNumber":1345,"sourceCode":"    if backend:\n        cmd.extend([\"--backend\", backend])\n    env = os.environ.copy()\n    if STATE_ROOT_ENV in os.environ:\n        env[STATE_ROOT_ENV] = os.environ[STATE_ROOT_ENV]\n    kwargs = _detached_kwargs(sd / \"daemon.log\")\n    proc = None\n    try:\n        proc = subprocess.Popen(cmd, env=env, **kwargs)\n    finally:\n        log_fh = kwargs.get(\"stdout\")\n        if hasattr(log_fh, \"close\"):\n            log_fh.close()\n    try:\n        deadline = time.monotonic() + timeout\n        last_error = None\n        while time.monotonic() < deadline:\n            if proc.poll() is not None:\n                raise DaemonError(f\"daemon exited during startup with code {proc.returncode}\")\n            try:\n                client = DaemonClient(palace_path)\n                client.health()\n                return client\n            except DaemonError as exc:\n                last_error = exc\n                time.sleep(0.1)\n        raise DaemonError(f\"daemon did not become ready: {last_error}\")\n    except BaseException:\n        # Readiness failed — don't leak an orphaned detached child holding the\n        # port, token, queue, and log handle. Kill and reap it before raising.\n        if proc is not None and proc.poll() is None:\n            try:\n                proc.kill()\n                proc.wait()\n            except Exception:  # noqa: BLE001 - cleanup best-effort\n                pass\n        raise","sourceCodeStart":1327,"sourceCodeEnd":1363,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/daemon.py#L1327-L1363","documentation":"DaemonError raised in start_daemon's readiness loop (mempalace/daemon.py:1345): the spawned daemon subprocess exited (proc.poll() is not None) before becoming healthy, with its exit code embedded in the message. The child is killed and reaped by the surrounding handler so no orphan holds the port/token/queue. Common underlying causes are visible in the daemon's log file.","triggerScenarios":"Daemon process crashing at import/startup (bad config, missing dependency, unsupported backend); port already bound causing immediate exit; permission errors creating state files; a Python version mismatch in the spawned interpreter.","commonSituations":"First daemon start after a config edit that introduced error 200/202/203-class problems; upgrade left incompatible state; the log file handle (stdout redirect) contains the traceback; another daemon raced to bind the port.","solutions":["Open the daemon log file (the path passed as stdout to Popen) and read the child's traceback — the exit code alone is secondary.","Fix the root cause it shows (config validation error, port conflict, permissions, missing backend package).","Verify no other daemon is already running (pid file, get_client_if_running) so the port is free.","Retry start_daemon after fixing; the cleanup path guarantees no half-spawned child remains."],"exampleFix":"# before\nclient = start_daemon(palace_path)  # exits code 1, opaque\n\n# after\ntry:\n    client = start_daemon(palace_path)\nexcept DaemonError as exc:\n    print(open(daemon_log_path).read())  # child traceback explains the exit code","handlingStrategy":"try-catch","validationCode":"from mempalace.daemon import get_client_if_running\n\nif get_client_if_running(palace_path) is None:\n    # validate config loads cleanly before spawning the daemon\n    from mempalace.config import load_config\n    load_config(palace_path)","typeGuard":null,"tryCatchPattern":"from mempalace.daemon import DaemonError\n\ntry:\n    client = start_daemon(palace_path)\nexcept DaemonError as exc:\n    if \"exited during startup\" in str(exc):\n        log = Path(daemon_log).read_text()  # child traceback explains the code\n        raise RuntimeError(f\"daemon crash:\\n{log}\") from exc\n    raise","preventionTips":["Read the daemon log file immediately when startup fails — the exit code is not enough.","Smoke-test config loading before spawning the daemon.","Ensure the port is free and the backend package is installed before start_daemon."],"tags":["daemon","startup","subprocess","crash"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}