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

  1. Ensure app_state.remote_access_port is set to the server's actual listening port (positive int) before the settings UI/API is exposed.
  2. If port assignment is lazy, block the Start button / API route until the port is known.
  3. 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

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


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/b3cf6fcc1c510482. Report an issue: GitHub.