unslothai/unsloth · warning · RuntimeError
server_lifecycle_changed
Error message
server_lifecycle_changed
What it means
Raised by start_remote_access() when the current studio tunnel control token no longer matches the admission captured at function entry. The tunnel controller rotates its token on lifecycle events (restart, new controller generation), so a mismatch means the world changed between capturing admission and acting on it. The call is aborted rather than acting on a stale generation.
Source
Thrown at studio/backend/utils/remote_access_settings.py:265
"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)
if url:
logger.info("Secure link access via Cloudflare: %s", url)
_open_remote_access_stop_response_admission()View on GitHub (pinned to 203007d190)
Solutions
- Re-read the current tunnel status and retry the start — the new generation will mint a fresh matching admission.
- Serialize remote-access settings operations client-side (disable the Start/Stop buttons while one is in flight) to avoid racing requests.
- If it recurs constantly, inspect logs for what keeps rotating the control token (crash loop, repeated restarts).
Defensive patterns
Strategy: retry
Try / catch
for attempt in range(3):
try:
return start_remote_access(app_state)
except RuntimeError as e:
if str(e) == 'server_lifecycle_changed' and attempt < 2:
time.sleep(0.5 * (attempt + 1))
continue
raise Prevention
- Serialize Start/Stop requests client-side so a token rotation cannot race your call.
- On mismatch, always re-fetch status before retrying — never replay blindly in a tight loop.
When it happens
Trigger: Calling start_remote_access() and, between capture_studio_tunnel_start_admission() and the token comparison, another lifecycle event rotates the control token — e.g. a concurrent stop/restart, controller regeneration, or shutdown racing the start request.
Common situations: Two settings requests racing (start and stop clicked in quick succession), a restart triggered while a start is in flight, or automation firing start during an update. Essentially a TOCTOU guard on tunnel generation.
Related errors
- server_shutting_down
- {block_reason} or operation_in_progress
- server_port_unavailable
- {block_reason} or not_settings_managed
- The linked-folder scope no longer exists
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/07099e1ed71b1c23.
Report an issue: GitHub.