unslothai/unsloth · error · RuntimeError
Could not find a free port in range {start}-{start + max_att
Error message
Could not find a free port in range {start}-{start + max_attempts - 1} What it means
RuntimeError from the port-picker in run.py: none of the max_attempts candidate ports starting at `start` were free (and, with avoid_own_studio, own-instance collisions abort earlier). Every offset in [start, start+max_attempts-1] was either occupied by another process or failed the bind probe.
Source
Thrown at studio/backend/run.py:826
host: str,
start: int,
max_attempts: int = 20,
avoid_own_studio: bool = False,
) -> int:
"""Find a free port from `start`, trying up to max_attempts ports.
``avoid_own_studio`` aborts rather than skipping past one of our own servers
in the fallback range, which would start a duplicate on a later port.
"""
for offset in range(max_attempts):
candidate = start + offset
if _is_port_free(host, candidate):
return candidate
if avoid_own_studio:
own = _own_studio_on_port(candidate, host)
if own is not None:
_abort_already_running(own, candidate)
raise RuntimeError(f"Could not find a free port in range {start}-{start + max_attempts - 1}")
from utils.paths.storage_roots import studio_root as _studio_root
# Legacy single-instance file; still read so `stop` finds an older build's server.
_PID_FILE = _studio_root() / "studio.pid"
PID_FILE_GLOB = "studio-*.pid"
# Deliberately not a .pid: everything that globs PID_FILE_GLOB expects a bound
# server with a port in the name, and a process that has not bound yet is not
# one. Only the sibling probe reads these.
STARTUP_MARKER_GLOB = "studio-starting-*.marker"
_OWN_STARTUP_MARKERS: "list[Path]" = []
_STARTUP_MARKER_HOOK_REGISTERED = False
def _pid_file_for_port(port: int) -> Path:
# PID in the name: 127.0.0.1 and ::1 can share a port, and one file per port
# would let the second bind overwrite the first.View on GitHub (pinned to 203007d190)
Solutions
- Free or pick a specific port explicitly (pass an explicit --port outside the busy range).
- Stop processes holding the range (ss -ltnp 'sport >= START' to identify them).
- Widen the ephemeral gap or change the start port if the OS ephemeral range overlaps.
- Retry after TIME_WAIT sockets expire (~60s) if a crash storm caused it.
Example fix
# before: range busy $ unsloth studio run # RuntimeError: Could not find a free port in range 8000-8009 # after: explicit free port $ ss -ltn 'sport >= 8000' $ unsloth studio run --port 8123
Defensive patterns
Strategy: validation
Validate before calling
import socket
def port_free(host: str, port: int) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.connect_ex((host, port)) != 0
if not port_free('127.0.0.1', 8000):
raise SystemExit('port 8000 busy — pass a different --port') Prevention
- Pass an explicit --port for scripted/CI launches instead of relying on range fallback
- Audit listeners with ss -ltnp when the range is busy
- Note Studio's own instances abort the scan deliberately — stop them rather than expecting a skip
When it happens
Trigger: Starting Studio while many ports in the fallback range are taken (other services, a range consumed by ephemeral connections, or several Studio instances already running); a small max_attempts combined with a busy range; Docker port-publishing reserving the span.
Common situations: Dev machine with many local servers; Linux ip_local_port_range overlapping the Studio range so ephemeral sockets randomly occupy candidates; previous crashed runs leaving sockets in TIME_WAIT.
Related errors
- Error: Invalid UNSLOTH_CPU_THREADS value {configured!r}: {ex
- UNSLOTH_CPU_THREADS must be a positive integer
- VirusTotal upload failed after {attempts} attempt(s): {last_
- Add a Provider connection block before running this recipe.
- '{repo}' is gated on Hugging Face and this model cannot be d
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/146830714eaa05cc.
Report an issue: GitHub.