unslothai/unsloth · error · ValueError

Auto-unload idle seconds must be a non-negative integer.

Error message

Auto-unload idle seconds must be a non-negative integer.

What it means

Raised by set_openai_auto_switch in openai_auto_switch_settings.py:296 when idle_seconds is provided but _coerce_int returns None. _coerce_int does max(0, int(value)); it fails (returns None) for None-like values, non-numeric strings, floats with decimals like "1.5", and containers. Negative ints are clamped to 0, not rejected here.

Source

Thrown at studio/backend/utils/openai_auto_switch_settings.py:296


def set_openai_auto_switch(
    enabled: Any,
    idle_seconds: Any,
    keep_kv: Any = None,
    auto_download: Any = None,
    api_only: Any = None,
    media_idle_seconds: Any = None,
) -> tuple[bool, int, bool, bool, bool, int]:
    """One-transaction write; ``None`` leaves a stored value untouched."""
    parsed_enabled = _coerce_bool(enabled)
    if parsed_enabled is None:
        raise ValueError("OpenAI auto-switch must be true or false.")
    parsed_idle = None
    if idle_seconds is not None:
        parsed_idle = _coerce_int(idle_seconds)
        if parsed_idle is None:
            raise ValueError("Auto-unload idle seconds must be a non-negative integer.")
        if 0 < parsed_idle < MIN_AUTO_UNLOAD_IDLE_SECONDS:
            raise ValueError(
                f"Auto-unload idle seconds must be 0 (off) or at least "
                f"{MIN_AUTO_UNLOAD_IDLE_SECONDS}."
            )
    parsed_media_idle = None
    if media_idle_seconds is not None:
        parsed_media_idle = _coerce_int(media_idle_seconds)
        if parsed_media_idle is None:
            raise ValueError("Media auto-unload idle seconds must be a non-negative integer.")
        if 0 < parsed_media_idle < MIN_AUTO_UNLOAD_IDLE_SECONDS:
            raise ValueError(
                f"Media auto-unload idle seconds must be 0 (off) or at least "
                f"{MIN_AUTO_UNLOAD_IDLE_SECONDS}."
            )
    parsed_keep_kv = None
    if keep_kv is not None:
        parsed_keep_kv = _coerce_bool(keep_kv)

View on GitHub (pinned to 203007d190)

Solutions

  1. Parse the input to an int before calling (e.g. int(str(value).strip()) with try/except)
  2. Send plain integers or integer strings like "120" from the client
  3. Reject fractional idle values in the form/UI layer
  4. Remember 0 means 'off' and negatives are clamped to 0, so only malformed types reach this error

Example fix

# before
set_openai_auto_switch(enabled=True, idle_seconds="90s")

# after
seconds = int("90")
set_openai_auto_switch(enabled=True, idle_seconds=seconds)
Defensive patterns

Strategy: validation

Validate before calling

def parse_idle_seconds(v) -> int | None:
    try:
        return max(0, int(str(v).strip()))
    except (TypeError, ValueError):
        return None

parsed = parse_idle_seconds(idle_seconds)
if idle_seconds is not None and parsed is None:
    raise HTTPException(400, "idle_seconds must be a non-negative integer")

Type guard

def is_coercible_int(v: object) -> bool:
    try:
        int(v)
        return True
    except (TypeError, ValueError):
        return False

Try / catch

try:
    set_openai_auto_switch(enabled=True, idle_seconds=idle_seconds)
except ValueError as exc:
    return {"ok": False, "error": str(exc)}, 400

Prevention

When it happens

Trigger: set_openai_auto_switch(enabled=True, idle_seconds="90s"), idle_seconds=1.5 (float with fraction via string), idle_seconds="1.5", or idle_seconds=[90]. Also idle_seconds="" or a dict.

Common situations: UI sends the raw text-field value ("120s", "1.5", "") instead of a parsed integer; configs carry floats; unit tests pass Decimal or float types.

Related errors


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