unslothai/unsloth · error · RuntimeError
server_port_unavailable
Error message
server_port_unavailable
What it means
Raised by start_remote_access() when app_state.remote_access_port is missing or invalid (not an int, or <= 0). The tunnel needs a concrete local port to expose; without one the start is refused before any worker thread is scheduled. This points at server wiring/configuration, not at the tunnel itself.
Source
Thrown at studio/backend/utils/remote_access_settings.py:273
capture_studio_tunnel_start_admission,
get_studio_tunnel_control_token,
)
admission = capture_studio_tunnel_start_admission()
if admission is None:
raise RuntimeError("server_shutting_down")
status = remote_access_status(app_state)
current = get_studio_tunnel_control_token()
if current[0] != admission[0]:
raise RuntimeError("server_lifecycle_changed")
if status["managed_by"] == "settings" and status["state"] in {"starting", "online"}:
return status
if not status["can_start"]:
raise RuntimeError(status["block_reason"] or "operation_in_progress")
port = getattr(app_state, "remote_access_port", None)
if not isinstance(port, int) or port <= 0:
raise RuntimeError("server_port_unavailable")
if get_studio_tunnel_control_token() != admission:
raise RuntimeError("server_lifecycle_changed")
def _start() -> None:
from cloudflare_tunnel import start_studio_tunnel
url = start_studio_tunnel(port, managed_by = "settings", admission = admission)
if url:
logger.info("Secure link access via Cloudflare: %s", url)
_open_remote_access_stop_response_admission()
with _worker_lock:
if not _worker_is_current(_start_worker, _start_worker_admission, admission):
_start_worker = threading.Thread(target = _start, daemon = True)
_start_worker_admission = admission
_start_worker.start()
return remote_access_status(app_state)
View on GitHub (pinned to 203007d190)
Solutions
- Ensure app_state.remote_access_port is set to the server's actual listening port (positive int) before the settings UI/API is exposed.
- If port assignment is lazy, block the Start button / API route until the port is known.
- Check server startup logs for a failed or skipped port configuration step.
Defensive patterns
Strategy: type-guard
Validate before calling
port = getattr(app_state, 'remote_access_port', None)
if not isinstance(port, int) or isinstance(port, bool) or port <= 0:
abort(409, 'remote access unavailable until server port is configured') Type guard
def has_valid_remote_access_port(app_state) -> bool:
port = getattr(app_state, 'remote_access_port', None)
return isinstance(port, int) and not isinstance(port, bool) and port > 0 Try / catch
try:
start_remote_access(app_state)
except RuntimeError as e:
if str(e) == 'server_port_unavailable':
log.error('app_state.remote_access_port unset — fix server wiring')
# config bug: do not retry, fix initialization
raise Prevention
- Set remote_access_port during app_state construction, before exposing settings routes.
- Add a startup assertion that remote_access_port is a positive int so misconfiguration fails fast at boot.
When it happens
Trigger: Calling start_remote_access(app_state) where app_state.remote_access_port is None (attribute never set), a string like '8080' (fails isinstance int), or 0/negative. Happens when the server was started with an incomplete app_state or a config path that skips the port assignment.
Common situations: Custom embedding of the studio server that constructs app_state manually and forgets remote_access_port; config migration dropping the port key; running the server in a mode where the HTTP listener port is determined lazily after settings load.
Related errors
- server_shutting_down
- server_lifecycle_changed
- {block_reason} or operation_in_progress
- {block_reason} or not_settings_managed
- dataset path must be relative or under a dataset root: {raw!
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/b3cf6fcc1c510482.
Report an issue: GitHub.