zylon-ai/private-gpt · warning

Server is already running with PID {existing_pid}

Error message

Server is already running with PID {existing_pid}

What it means

CLI error from `private-gpt serve` (private_gpt/cli/commands/serve.py). Before binding, serve checks a PID file: if it exists and os.kill(pid, 0) succeeds (a live process owns that PID), it prints 'Server is already running with PID <n>' to stderr and exits 1. A stale PID file (ProcessLookupError) is ignored and cleaned up implicitly by proceeding.

Source

Thrown at private_gpt/cli/commands/serve.py:42

    ),
    log_level: str = typer.Option(
        "info", "--log-level", help="debug | info | warn | error"
    ),
    pid_file: Path | None = PID_FILE_OPTION,
) -> None:
    """Start the HTTP server."""
    s = settings()
    resolved_port = port if port is not None else s.server.port
    logger.info(
        "Starting server with profiles=%s on port %s", active_profiles, resolved_port
    )

    if pid_file and pid_file.exists():
        try:
            existing_pid = int(pid_file.read_text().strip())
            os.kill(existing_pid, 0)
            typer.echo(f"Server is already running with PID {existing_pid}", err=True)
            raise SystemExit(1)
        except ProcessLookupError:
            pass  # stale PID file

    if pid_file:
        pid_file.parent.mkdir(parents=True, exist_ok=True)
        pid_file.write_text(str(os.getpid()))

    def _on_sigterm(signum: int, frame: object) -> None:
        if pid_file and pid_file.exists():
            pid_file.unlink(missing_ok=True)
        raise SystemExit(0)

    signal.signal(signal.SIGTERM, _on_sigterm)

    try:
        uvicorn.run(
            "private_gpt.main:app",
            host=host,

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Use the existing server instead of starting another: check `curl http://localhost:<port>/health`.
  2. Stop the old instance: `kill <existing_pid>` (the PID is printed in the message), wait for exit, then re-run serve.
  3. If the PID belongs to an unrelated process (PID reuse), delete the PID file and start again.
  4. In scripts, guard with a health check before invoking serve.

Example fix

// before
$ private-gpt serve
Server is already running with PID 4242

// after
$ kill 4242 && sleep 1
$ private-gpt serve
Defensive patterns

Strategy: validation

Validate before calling

import urllib.request

def already_serving(port: int) -> bool:
    try:
        urllib.request.urlopen(f"http://127.0.0.1:{port}/health", timeout=1)
        return True
    except Exception:
        return False

# skip `private-gpt serve` when already_serving(port) is True

Prevention

When it happens

Trigger: Running `private-gpt serve` twice concurrently; a previous server still running in another terminal/tmux; the PID from the file being reused by an unrelated live process (rare PID-reuse false positive).

Common situations: Forgotten background server from an earlier session; CI job or supervisor restarting serve while the old instance lives; container restart where the old process survived.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/ba461b58e411fa8f. Report an issue: GitHub.