MemPalace/mempalace · error · DaemonError

daemon token not found for {palace_path}

Error message

daemon token not found for {palace_path}

What it means

DaemonError from read_token() (mempalace/daemon.py:162): it tries to read the shared-secret token file at <state_dir>/token and re-raises any OSError (missing file, permission denied, unreadable) as DaemonError. The token is the bearer credential DaemonClient sends for HTTP auth, so without it the daemon cannot be used from this client.

Source

Thrown at mempalace/daemon.py:162


def ensure_token(palace_path: str) -> str:
    token_path = state_dir(palace_path) / "token"
    if token_path.exists():
        token = token_path.read_text(encoding="utf-8").strip()
        if token:
            return token
    token = secrets.token_urlsafe(32)
    _write_private(token_path, token + "\n")
    return token


def read_token(palace_path: str) -> str:
    token_path = state_dir(palace_path) / "token"
    try:
        return token_path.read_text(encoding="utf-8").strip()
    except OSError as exc:
        raise DaemonError(f"daemon token not found for {palace_path}") from exc


def endpoint_path(palace_path: str) -> Path:
    return state_dir(palace_path) / "endpoint.json"


def pid_path(palace_path: str) -> Path:
    return state_dir(palace_path) / "pid"


def queue_path(palace_path: str) -> Path:
    return state_dir(palace_path) / "queue.sqlite3"


def _read_endpoint(palace_path: str) -> dict[str, Any]:
    try:
        with open(endpoint_path(palace_path), encoding="utf-8") as fh:
            return json.load(fh)

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Start the daemon first with start_daemon(palace_path) (or ensure_client with auto_start=True) so ensure_token creates the token.
  2. Verify the token file exists and is readable: ls -l <state_dir>/token; if permissions are wrong, restart the daemon under the correct user.
  3. If the state dir was deleted or corrupted, stop any running daemon and let ensure_token regenerate the token.
  4. Check the state directory path resolution (canonical_palace_path / state_dir) matches between the writer and reader of the token.

Example fix

# before
client = DaemonClient(palace_path)  # DaemonError if never started

# after
client = ensure_client(palace_path, auto_start=True)  # starts daemon + ensures token
Defensive patterns

Strategy: fallback

Validate before calling

from mempalace import daemon

def token_ready(palace_path: str) -> bool:
    return (daemon.state_dir(palace_path) / "token").is_file()

Try / catch

from mempalace.daemon import DaemonError, ensure_client

try:
    client = DaemonClient(palace_path)
except DaemonError:
    client = ensure_client(palace_path, auto_start=True)  # start daemon / mint token

Prevention

When it happens

Trigger: Calling DaemonClient / get_client_if_running before the daemon has ever started (ensure_token hasn't created the file); running the client as a different OS user than the one that started the daemon (0600-perm token file via _write_private); deleting the palace state directory; a read-only or corrupted state dir.

Common situations: First use on a machine where start_daemon was never invoked; mixed-user setups (daemon under your user, hook under another); cleanup scripts that rm -rf the state dir while the daemon still runs; moving the palace directory without its state dir.

Related errors


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