unslothai/unsloth · error · ValueError

lr_scheduler must be one of {', '.join(sorted(_LR_SCHEDULERS

Error message

lr_scheduler must be one of {', '.join(sorted(_LR_SCHEDULERS))}; got {self.lr_scheduler!r}

What it means

The validator rejected an lr_scheduler name not present in the _LR_SCHEDULERS allowlist. The trainer maps this string to a concrete learning-rate schedule; an unknown name would otherwise KeyError or silently fall back later in the loop. The message includes the sorted list of valid names and echoes the offending value.

Source

Thrown at studio/backend/core/training/diffusion_train_common.py:1046

        ):
            raise ValueError(
                f"'{resolved_family}' trains at a resolution that is a multiple of "
                f"{_VIDEO_RESOLUTION_MULTIPLE} (its VAE compresses space by that factor); "
                f"got {self.resolution}."
            )
        if self.mixed_precision not in ("bf16", "fp16", "no"):
            raise ValueError("mixed_precision must be one of bf16 / fp16 / no")
        # torch.manual_seed unpacks int64/uint64, so anything wider raises inside the trainer, after eviction. Catch it here.
        if not -(2**63) <= int(self.seed) <= 2**64 - 1:
            raise ValueError("seed must fit in torch's 64-bit range")
        # Refuse fp16 for a bf16-only DiT family up front, before evicting resident models.
        if self.mixed_precision == "fp16" and resolved_family in _FORCE_BF16_FAMILIES:
            raise ValueError(
                f"'{resolved_family}' LoRA training requires bf16: fp16 overflows its fp32 "
                f"RoPE / embedder internals. Set mixed precision to bf16."
            )
        if str(self.lr_scheduler) not in _LR_SCHEDULERS:
            raise ValueError(
                f"lr_scheduler must be one of {', '.join(sorted(_LR_SCHEDULERS))}; "
                f"got {self.lr_scheduler!r}"
            )
        if not 1 <= int(self.cache_variants) <= 16:
            raise ValueError("cache_variants must be between 1 and 16")
        # Checkpointing knobs. Rejected here, before the route evicts resident GPU models, rather than deep in the loop.
        try:
            save_steps = int(self.save_steps or 0)
            save_total_limit = int(self.save_total_limit or 0)
        except (TypeError, ValueError) as exc:
            raise ValueError(
                f"save_steps / save_total_limit must be whole numbers, got "
                f"{self.save_steps!r} / {self.save_total_limit!r}"
            ) from exc
        if save_steps < 0:
            raise ValueError("save_steps must be >= 0 (0 disables periodic checkpoints)")
        if save_total_limit < 0:
            raise ValueError("save_total_limit must be >= 0 (0 keeps every checkpoint)")

View on GitHub (pinned to 203007d190)

Solutions

  1. Read the error message: it lists every valid scheduler name — use one verbatim.
  2. Validate/normalize before submitting: str(lr_scheduler).strip() and check membership in the allowed set.
  3. Replace UI free-text with a dropdown sourced from the same allowlist.

Example fix

# before
config = TrainConfig(lr_scheduler='CosineAnnealingLR')

# after
config = TrainConfig(lr_scheduler='cosine')  # a name from the error's allowlist
Defensive patterns

Strategy: validation

Validate before calling

LR_SCHEDULERS = {"constant", "cosine", "linear", ...}  # mirror the trainer's allowlist

def check_lr_scheduler(v) -> str:
    s = str(v or "constant").strip()
    if s not in LR_SCHEDULERS:
        raise ValueError(f"lr_scheduler must be one of {sorted(LR_SCHEDULERS)}, got {v!r}")
    return s

Type guard

def is_valid_lr_scheduler(v) -> bool:
    return str(v or "constant").strip() in LR_SCHEDULERS

Try / catch

try:
    session.submit_training(config)
except ValueError as e:
    if "lr_scheduler" in str(e):
        config.lr_scheduler = "constant"  # neutral default
        session.submit_training(config)
    else:
        raise

Prevention

When it happens

Trigger: Passing lr_scheduler values with wrong casing, whitespace, or different vocabulary ('CosineAnnealing', 'cosine_annealing ', 'polynomial'), or names from other training stacks (HuggingFace/DeepSpeed spellings) that do not match this trainer's set.

Common situations: Copy-pasting scheduler names from HuggingFace examples into this Studio's config; UI free-text input instead of a dropdown; casing/typo mistakes in YAML.

Related errors


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