unslothai/unsloth · warning · RuntimeError

{block_reason} or not_settings_managed

Error message

{block_reason} or not_settings_managed

What it means

Raised by stop_remote_access() when the tunnel is not managed by 'settings' — status['managed_by'] is something else (e.g. an auto-start flow or a foreign owner). The message is status['block_reason'] when set, otherwise the literal 'not_settings_managed'. Settings-owned stop only cancels settings-owned tunnels; already-off/stopping states return idempotently instead of raising.

Source

Thrown at studio/backend/utils/remote_access_settings.py:312

    global _stop_worker, _stop_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["state"] == "off" and status["managed_by"] is None:
        return status
    if status["state"] == "stopping" and status["managed_by"] == "settings":
        return status
    if status["managed_by"] != "settings":
        raise RuntimeError(status["block_reason"] or "not_settings_managed")

    if get_studio_tunnel_control_token() != admission:
        raise RuntimeError("server_lifecycle_changed")

    def _stop() -> None:
        global _stop_worker_admission
        from cloudflare_tunnel import get_studio_tunnel_status, stop_studio_tunnel

        # A stop can beat the newly-created start worker to the controller. Wait
        # until it claims settings ownership, then cancel that generation. Bounded:
        # a start that never claims it (foreign owner, bailed on admission) must
        # not defer the user's Stop for the probe deadline.
        deadline = time.monotonic() + _STOP_OWNERSHIP_WAIT
        while _worker_alive(_start_worker) and time.monotonic() < deadline:
            if get_studio_tunnel_status()["managed_by"] == "settings":
                break
            time.sleep(0.02)
        current = get_studio_tunnel_control_token()

View on GitHub (pinned to 203007d190)

Solutions

  1. Read block_reason in the error — it identifies the owning flow.
  2. Stop the tunnel through its owner: disable the auto-start preference for boot-owned tunnels, or use the owning component's stop path.
  3. Only use stop_remote_access() for tunnels the settings UI itself started (managed_by == 'settings').
Defensive patterns

Strategy: validation

Validate before calling

status = remote_access_status(app_state)
if status['managed_by'] != 'settings':
    abort(409, f"tunnel managed by {status['managed_by'] or 'another owner'}; "
               f"{status['block_reason'] or 'stop it from its owning flow'}")

Type guard

def is_settings_managed(status: dict) -> bool:
    return status.get('managed_by') == 'settings'

Try / catch

try:
    stop_remote_access(app_state)
except RuntimeError as e:
    msg = str(e)
    if msg == 'not_settings_managed' or 'managed' in msg:
        # route to the owner: disable auto-start pref or use the owning component's stop
        disable_tunnel_autostart()
    else:
        raise

Prevention

When it happens

Trigger: Calling stop_remote_access() while managed_by is neither 'settings' nor None-with-state-off — e.g. the tunnel was started by the auto-start preference flow, an external tool, or another component that claimed ownership.

Common situations: Auto-start enabled at boot starts the tunnel under a different owner; user later tries to stop it via the settings toggle and hits this. Or an external cloudflared instance was wired in manually.

Related errors


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