unslothai/unsloth · error · ValueError
learning_rate must be a number, got {self.learning_rate!r}
Error message
learning_rate must be a number, got {self.learning_rate!r} What it means
learning_rate is coerced with float() because the Studio config path can deliver it as a string ('1e-4'). If the value is not numeric and not a numeric string, the coercion raises TypeError/ValueError and the config re-raises with the original value echoed.
Source
Thrown at studio/backend/core/training/diffusion_train_common.py:1177
"flow_shift must be a finite number > 0 (1.0 disables the shift), or 'auto'"
)
try:
cfg_dropout = float(self.cfg_dropout or 0.0)
except (TypeError, ValueError) as exc:
raise ValueError(f"cfg_dropout must be a number, got {self.cfg_dropout!r}") from exc
if not 0.0 <= cfg_dropout <= 1.0:
raise ValueError("cfg_dropout must be between 0 and 1")
weighting_scheme = str(self.weighting_scheme or "none").strip().lower()
if weighting_scheme not in ("none", "bell"):
raise ValueError("weighting_scheme must be one of none / bell")
# A zero/negative gamma would zero out (or invert) the min-SNR weight and silently train on a degenerate loss; None is the documented disable.
if self.snr_gamma is not None and float(self.snr_gamma) <= 0:
raise ValueError("snr_gamma must be > 0, or null to disable min-SNR weighting")
# learning_rate can arrive as a string ("1e-4") from the Studio config path, so coerce it before AdamW sees it.
try:
learning_rate = float(self.learning_rate)
except (TypeError, ValueError) as exc:
raise ValueError(f"learning_rate must be a number, got {self.learning_rate!r}") from exc
if learning_rate <= 0:
raise ValueError("learning_rate must be > 0")
alpha = self.lora_alpha if self.lora_alpha is not None else self.lora_rank
targets = tuple(self.lora_target_modules) or DEFAULT_LORA_TARGETS
# A blank Hub token (the Studio default when none is configured) must load anonymously, not as an explicit empty credential.
token = self.hf_token.strip() if isinstance(self.hf_token, str) else self.hf_token
from core.inference.diffusion_families import (
_is_local_path,
mirror_repo,
prefer_ungated_mirror,
upstream_is_gated,
)
if resolved_family == "sdxl":
fetch_base_model = self.base_model
else:
fetch_base_model = prefer_ungated_mirror(self.base_model, token or None)
# For a GATED upstream and no token, the cache preference has to be overridden: theView on GitHub (pinned to 203007d190)
Solutions
- Pass a plain number (0.0001) or a clean numeric string ('1e-4').
- Sanitize free-text input: strip whitespace and reject anything float() cannot parse before it reaches the config.
- Check for stray characters pasted alongside the value (units, commas, currency symbols).
Example fix
# before cfg = DiffusionLoraConfig(learning_rate='0.0001 ') # ok, but '1e-4 lr' fails # after cfg = DiffusionLoraConfig(learning_rate='1e-4') # or 0.0001
Defensive patterns
Strategy: validation
Validate before calling
def coerce_lr(v):
if isinstance(v, str):
v = v.strip().replace(',', '') # tolerate '1e-4 ' / '0,0001'
lr = float(v)
if lr <= 0:
raise ValueError('learning_rate must be > 0')
return lr Type guard
def is_valid_learning_rate(v) -> bool:
try:
return float(v) > 0
except (TypeError, ValueError):
return False Prevention
- Treat learning_rate as a required numeric field in forms; reject placeholder text at submission.
- Run float() coercion in your config loader so bad values fail with your own error message.
When it happens
Trigger: learning_rate='lr', '1e-4x', a list, or None handled incorrectly at the call site (None raises TypeError here, unlike cfg_dropout's 'or' fallback).
Common situations: Hand-edited YAML/JSON with a typo; a UI field left with placeholder text like 'e.g. 0.0001'; unit-suffixed strings like '4e-5lr'.
Related errors
- base_precision={base_precision!r} trains in bf16 compute; se
- flow_shift must be a positive number or 'auto', got {self.fl
- cfg_dropout must be a number, got {self.cfg_dropout!r}
- cfg_dropout must be between 0 and 1
- weighting_scheme must be one of none / bell
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/a0f26d2e5cdd24b6.
Report an issue: GitHub.