ZhuLinsen/daily_stock_analysis · critical · RuntimeError
FastAPI port is not available: {host}:{port}
Error message
FastAPI port is not available: {host}:{port} What it means
Before handing the port to uvicorn, main.py probes it by binding a raw socket; if the OS refuses the bind, startup aborts with RuntimeError. Bind failures mean either another process already listens on host:port (EADDRINUSE) or the host address does not exist on this machine (e.g. binding a LAN IP while offline, or IPv6 syntax on an IPv4-only stack).
Source
Thrown at main.py:1199
def start_api_server(host: str, port: int, config: Config) -> None:
"""
在后台线程启动 FastAPI 服务
Args:
host: 监听地址
port: 监听端口
config: 配置对象
"""
import socket
import threading
import uvicorn
probe = socket.socket(socket.AF_INET6 if ":" in host else socket.AF_INET, socket.SOCK_STREAM)
try:
probe.bind((host, port))
except OSError as exc:
raise RuntimeError(f"FastAPI port is not available: {host}:{port}") from exc
finally:
probe.close()
level_name = (config.log_level or "INFO").lower()
use_config_signal_handlers = True
uvicorn_kwargs = {
"host": host,
"port": port,
"log_level": level_name,
"log_config": None,
}
# Import the ASGI app object in the calling thread instead of handing uvicorn
# the "api.app:app" import string. With the string, uvicorn imports the app
# lazily inside the server thread, and that import (litellm + the full app
# tree, ~10s+ on constrained hosts) runs inside the startup probe window
# below, tripping the 3.0s timeout and causing a restart loop on slower
# machines. Importing first keeps the heavy work out of the probe window;
# genuine import failures still surface immediately to the caller.View on GitHub (pinned to 5159bd72e8)
Solutions
- Find and stop the occupant: ss -ltnp 'sport = :<port>' or lsof -i :<port>, then kill it — or start your instance on a different port.
- Verify the host value resolves on this machine: binding 0.0.0.0 or 127.0.0.1 always works; a specific LAN IP fails when the interface is absent.
- If a stale process from a crashed run holds the socket, kill it (ps aux | grep main.py) rather than changing ports.
- In Docker, check for duplicate port mappings in docker-compose.
Example fix
# before $ python main.py --serve # RuntimeError: FastAPI port is not available: 0.0.0.0:8000 # after $ ss -ltnp 'sport = :8000' # find PID holding 8000 $ kill <PID> $ python main.py --serve
Defensive patterns
Strategy: validation
Validate before calling
import socket
def port_free(host: str, port: int) -> bool:
family = socket.AF_INET6 if ":" in host else socket.AF_INET
with socket.socket(family, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind((host, port))
return True
except OSError:
return False
assert port_free(host, port), f"{host}:{port} occupied" Try / catch
try:
run_fastapi(host, port, config)
except RuntimeError as e:
if "port is not available" in str(e):
port = find_free_port() # or prompt user; then retry
run_fastapi(host, port, config)
else:
raise Prevention
- Probe the port before startup (the script already does; do it in orchestrators too).
- Give dev servers non-default or ephemeral ports to avoid collisions.
- Always stop previous instances before starting a new one (check ps / ss).
When it happens
Trigger: Previous instance of the server (--serve/--serve-only) still running; another service occupying the port (default uvicorn port 8000 is commonly taken); host set to an interface that is down or misconfigured; Docker container binding a port already published by a sibling container; IPv6 host string on a kernel without IPv6.
Common situations: Running python main.py --serve twice; port 8000 grabbed by another dev server; config/env PORT mismatch after copying .env between machines; firewall/SELinux denying bind on non-loopback hosts.
Related errors
- FastAPI server failed to start: {host}:{port}; {startup_erro
- FastAPI 服务器启动后立即退出: {host}:{port}
- FastAPI 服务在 {timeout_seconds:.1f}s 内未完成启动: {host}:{port}
- Hermes BASE_URL contains an invalid port
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/6db03d29b8e2fda1.
Report an issue: GitHub.