{"record":{"id":"8d71e465015a77ff","repo":"sgl-project/sglang","slug":"failed-to-find-available-port-after-max-attempts","errorCode":null,"errorMessage":"Failed to find available port after {max_attempts} attempts (started from port {original_port})","messagePattern":"Failed to find available port after (.+?) attempts \\(started from port (.+?)\\)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/server_args/server_args.py","lineNumber":2838,"sourceCode":"        original_port = port\n        avoid = avoid or set()\n\n        while attempts < max_attempts:\n            if port not in avoid and is_port_available(port):\n                if attempts > 0:\n                    logger.info(\n                        f\"Port {original_port} was unavailable, using port {port} instead\"\n                    )\n                return port\n\n            attempts += 1\n            if port < 60000:\n                port += port_inc\n            else:\n                # Wrap around with randomization to avoid collision\n                port = 5000 + random.randint(0, 1000)\n\n        raise RuntimeError(\n            f\"Failed to find available port after {max_attempts} attempts \"\n            f\"(started from port {original_port})\"\n        )\n\n    @staticmethod\n    def _extract_dynamic_component_map(\n        unknown_args: list[str],\n        *,\n        option_prefixes: tuple[str, ...],\n        alias_suffix: str,\n    ) -> tuple[dict[str, str], list[str]]:\n        component_values: dict[str, str] = {}\n        remaining: list[str] = []\n        i = 0\n        while i < len(unknown_args):\n            arg = unknown_args[i]\n            key_part = arg.split(\"=\", 1)[0] if \"=\" in arg else arg\n            component = None","sourceCodeStart":2820,"sourceCodeEnd":2856,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/server_args/server_args.py#L2820-L2856","documentation":"Raised by ServerArgs.settle_port when probing for a free TCP port: starting from the requested port it increments (wrapping past 60000 back into the 5000-6000 range with randomization) and after max_attempts probes still found no bindable port. It means the port range is saturated or the process lacks permission to bind.","triggerScenarios":"Calling ServerArgs.from_cli_args / prepare_server_args on a machine where the candidate port range (port..port+max_attempts, or 5000-6000 after wrap) is fully occupied, e.g. many SGLang/multimodal_gen server instances already listening, or firewall/permission restrictions blocking binds.","commonSituations":"Launching multiple test workers or CI shards on one host that each auto-allocate ports; containers with very restricted ephemeral port ranges; a stale server still holding the port; port set below 1024 without root.","solutions":["Free the occupied ports (stop stale servers: lsof -i :PORT / kill) or pass an explicit free --port / port argument.","Pick a port in a range you know is open, verified beforehand with a socket bind test.","If running many instances, stagger starting ports far apart or reduce concurrency of launches.","Check container/host firewall or sysctl net.ipv4.ip_local_port_range if binds fail even on free ports."],"exampleFix":"# before\npython -m sglang.multimodal_gen.server --port 5000  # many shards, all collide\n# after\npython -m sglang.multimodal_gen.server --port $(python -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\")","handlingStrategy":"retry","validationCode":"import socket\n\ndef free_port(start: int, attempts: int = 100) -> int:\n    for p in range(start, start + attempts):\n        with socket.socket() as s:\n            if s.connect_ex((\"127.0.0.1\", p)) != 0:\n                return p\n    raise RuntimeError(\"no free port\")","typeGuard":null,"tryCatchPattern":"try:\n    args = ServerArgs.from_cli_args(cli)\nexcept RuntimeError as e:\n    if \"Failed to find available port\" in str(e):\n        args = ServerArgs.from_cli_args(cli + [\"--port\", str(free_port(20000))])\n    else:\n        raise","preventionTips":["Probe a port with a socket bind before launching.","Allocate staggered starting ports per worker/CI shard.","Kill stale servers before relaunching.","Expose port collision as a retryable condition in launch scripts."],"tags":["network","port-allocation","server-startup","configuration"],"backgroundTag":"address-in-use","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}