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
- Use the existing server instead of starting another: check `curl http://localhost:<port>/health`.
- Stop the old instance: `kill <existing_pid>` (the PID is printed in the message), wait for exit, then re-run serve.
- If the PID belongs to an unrelated process (PID reuse), delete the PID file and start again.
- 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
- Health-check the port before invoking serve in scripts.
- Kill or reuse the printed existing PID rather than fighting the guard.
- Clean stale PID files after crashes.
- Run one serve per port; use separate ports for parallel instances.
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
- Binary not found in PATH: {binary!r}
- Server did not become ready within {_HEALTH_TIMEOUT}s
- Unknown command: {cmd!r}
- Redis semaphore dependencies are not installed. Install with
- Unsupported semaphore mode: {mode!r}. Available: {', '.join(
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/ba461b58e411fa8f.
Report an issue: GitHub.