MemPalace/mempalace · error · DaemonError

daemon endpoint missing port

Error message

daemon endpoint missing port

What it means

DaemonError from DaemonClient.__init__ (mempalace/daemon.py:1110): endpoint.json was read successfully but contains no 'port' key. The endpoint file records where the daemon listens; a port-less file means it was written by an incompatible/older version, was hand-edited, or was truncated in a way that still parses as JSON.

Source

Thrown at mempalace/daemon.py:1110

    for stale in (endpoint_path(palace_path), pid_path(palace_path)):
        try:
            stale.unlink()
        except OSError:
            pass
    for key, value in previous_env.items():
        if value is None:
            os.environ.pop(key, None)
        else:
            os.environ[key] = value


class DaemonClient:
    def __init__(self, palace_path: str):
        self.palace_path = canonical_palace_path(palace_path)
        endpoint = _read_endpoint(self.palace_path)
        port = endpoint.get("port")
        if port is None:
            raise DaemonError("daemon endpoint missing port")
        # Don't read the token until we trust the endpoint points at a live
        # process we started: a stale endpoint whose pid is dead may have its
        # port reused by an unrelated process, and we must not send our bearer
        # token there.
        pid = endpoint.get("pid")
        if pid is not None and not _pid_alive(int(pid)):
            raise DaemonError("daemon endpoint pid is not alive")
        self.token = read_token(self.palace_path)
        self.host = endpoint.get("host") or HOST
        self.port = int(port)
        # The daemon is always on 127.0.0.1, so a request must never go through
        # an HTTP proxy. Building an opener with an empty ProxyHandler bypasses
        # urllib's proxy discovery entirely. On macOS that discovery
        # (urllib.request._scproxy, via the SystemConfiguration framework) runs
        # on the first request to any host and is NOT bounded by the per-request
        # timeout — on a CI runner with no network it can hang for tens of
        # seconds, which looks exactly like the daemon never came up. A no-proxy
        # opener is the correct production choice here and also removes that hang.

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Stop the daemon if any is running, delete the stale endpoint.json in the state dir, and restart so it is rewritten in the current format.
  2. If you control the endpoint file (tests), always include both 'port' and 'pid' keys.
  3. Check the daemon log for the startup that produced the file and confirm version match between client and daemon.

Example fix

# before: hand-written endpoint
{"host": "127.0.0.1"}

# after: let the daemon write it (delete stale file and restart)
# {"host": "127.0.0.1", "port": 52341, "pid": 12345}
Defensive patterns

Strategy: validation

Validate before calling

import json
from mempalace import daemon

def endpoint_has_port(palace_path: str) -> bool:
    try:
        return "port" in json.loads(daemon.endpoint_path(palace_path).read_text())
    except (OSError, json.JSONDecodeError):
        return False

Type guard

def is_valid_endpoint(ep: object) -> bool:
    return isinstance(ep, dict) and isinstance(ep.get("port"), int)

Try / catch

from mempalace.daemon import DaemonError

try:
    client = DaemonClient(palace_path)
except DaemonError:
    # stale/incompatible endpoint — clear it and restart the daemon
    daemon.endpoint_path(palace_path).unlink(missing_ok=True)
    client = start_daemon(palace_path)

Prevention

When it happens

Trigger: A stale endpoint.json from an older daemon version that recorded only host/pid; manual editing of the file; a JSON object like {} left behind by a failed write or test; concurrent format change after upgrade without cleanup.

Common situations: Upgrading MemPalace while an old endpoint.json persists in the state dir; test fixtures writing minimal endpoint files; state dirs shared/copied between machines.

Related errors


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