{"record":{"id":"6db03d29b8e2fda1","repo":"ZhuLinsen/daily_stock_analysis","slug":"fastapi-port-is-not-available-host-port","errorCode":null,"errorMessage":"FastAPI port is not available: {host}:{port}","messagePattern":"FastAPI port is not available: (.+?):(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"main.py","lineNumber":1199,"sourceCode":"\ndef start_api_server(host: str, port: int, config: Config) -> None:\n    \"\"\"\n    在后台线程启动 FastAPI 服务\n\n    Args:\n        host: 监听地址\n        port: 监听端口\n        config: 配置对象\n    \"\"\"\n    import socket\n    import threading\n    import uvicorn\n\n    probe = socket.socket(socket.AF_INET6 if \":\" in host else socket.AF_INET, socket.SOCK_STREAM)\n    try:\n        probe.bind((host, port))\n    except OSError as exc:\n        raise RuntimeError(f\"FastAPI port is not available: {host}:{port}\") from exc\n    finally:\n        probe.close()\n\n    level_name = (config.log_level or \"INFO\").lower()\n    use_config_signal_handlers = True\n    uvicorn_kwargs = {\n        \"host\": host,\n        \"port\": port,\n        \"log_level\": level_name,\n        \"log_config\": None,\n    }\n    # Import the ASGI app object in the calling thread instead of handing uvicorn\n    # the \"api.app:app\" import string. With the string, uvicorn imports the app\n    # lazily inside the server thread, and that import (litellm + the full app\n    # tree, ~10s+ on constrained hosts) runs inside the startup probe window\n    # below, tripping the 3.0s timeout and causing a restart loop on slower\n    # machines. Importing first keeps the heavy work out of the probe window;\n    # genuine import failures still surface immediately to the caller.","sourceCodeStart":1181,"sourceCodeEnd":1217,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/main.py#L1181-L1217","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n$ python main.py --serve  # RuntimeError: FastAPI port is not available: 0.0.0.0:8000\n\n# after\n$ ss -ltnp 'sport = :8000'   # find PID holding 8000\n$ kill <PID>\n$ python main.py --serve","handlingStrategy":"validation","validationCode":"import socket\n\ndef port_free(host: str, port: int) -> bool:\n    family = socket.AF_INET6 if \":\" in host else socket.AF_INET\n    with socket.socket(family, socket.SOCK_STREAM) as s:\n        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n        try:\n            s.bind((host, port))\n            return True\n        except OSError:\n            return False\n\nassert port_free(host, port), f\"{host}:{port} occupied\"","typeGuard":null,"tryCatchPattern":"try:\n    run_fastapi(host, port, config)\nexcept RuntimeError as e:\n    if \"port is not available\" in str(e):\n        port = find_free_port()  # or prompt user; then retry\n        run_fastapi(host, port, config)\n    else:\n        raise","preventionTips":["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)."],"tags":["server","port","startup","socket"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}