unslothai/unsloth · warning · RuntimeError
server_shutting_down
Error message
server_shutting_down
What it means
Raised by start_remote_access() when capture_studio_tunnel_start_admission() returns None, meaning the server is in (or entering) shutdown. Admission tokens gate tunnel start/stop operations so no new tunnel worker is spawned on a dying process. This is a lifecycle-state error, not a tunnel failure — retrying after shutdown completes (or on restart) is the path forward.
Source
Thrown at studio/backend/utils/remote_access_settings.py:261
# documents that those do not support Server-Sent Events. Measured: an
# SSE endpoint returns 200 with text/event-stream through the tunnel but
# delivers no events. So responses are only streamable while no tunnel
# is carrying them.
"streaming_supported": status["url"] is None,
}
def start_remote_access(app_state) -> dict:
"""Schedule a settings-owned start. Repeated requests are idempotent."""
global _start_worker, _start_worker_admission
from cloudflare_tunnel import (
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)View on GitHub (pinned to 203007d190)
Solutions
- Wait for the server restart to finish, then re-issue the start request — the new process captures admissions normally.
- If using the API, treat 'server_shutting_down' as a transient signal and retry with backoff once the health endpoint responds.
- Check server logs to confirm why it was shutting down (update applied, SIGTERM, crash) if the shutdown was unexpected.
Defensive patterns
Strategy: retry
Validate before calling
def server_healthy() -> bool:
try:
return requests.get(f'{base}/health', timeout=2).ok
except requests.RequestException:
return False Try / catch
try:
start_remote_access(app_state)
except RuntimeError as e:
if str(e) == 'server_shutting_down':
wait_until(server_healthy, timeout=60)
start_remote_access(app_state) # fresh process, fresh admission
else:
raise Prevention
- Disable remote-access controls while a restart/update is known to be in flight.
- Treat lifecycle errors as distinct from tunnel errors in clients: retry the former, surface the latter.
When it happens
Trigger: Calling start_remote_access(app_state) while the studio server process is shutting down: the admission capture returns None the moment shutdown begins, so any racing Start request from the settings UI or API gets this RuntimeError.
Common situations: A user clicks 'enable secure link' in the settings page at the same moment the server is restarting (update flow, manual restart, or crash). Automation scripts issuing start calls during a deployment window.
Related errors
- server_lifecycle_changed
- {block_reason} or operation_in_progress
- server_port_unavailable
- {block_reason} or not_settings_managed
- No export subprocess running
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/97efbf74a64dabac.
Report an issue: GitHub.