unslothai/unsloth · error · ValueError
learning_rate must be < 1.0 (got {lr!r}); values that large
Error message
learning_rate must be < 1.0 (got {lr!r}); values that large always diverge training What it means
Raised by the _parse_lr parser when the learning rate is >= _MAX_LR_VALUE (1.0). Learning rates of 1.0 or more always diverge training, so the parser enforces a hard ceiling rather than letting the job start and crash the GPU worker later. The bound is strict: exactly 1.0 is rejected too.
Source
Thrown at studio/backend/models/training.py:95
"access_key_id and secret_access_key"
)
return self
def _parse_lr(v: Any) -> float:
"""Parse learning_rate as a positive float strictly below _MAX_LR_VALUE."""
if v is None:
raise ValueError("learning_rate is required")
if isinstance(v, bool):
raise ValueError("learning_rate must be a number, not a bool")
try:
lr = float(v)
except (TypeError, ValueError):
raise ValueError(f"learning_rate must be parseable as float (got {v!r})")
if not (lr > 0.0):
raise ValueError(f"learning_rate must be > 0 (got {lr!r}); typical range is 1e-6 .. 1e-3")
if lr >= _MAX_LR_VALUE:
raise ValueError(
f"learning_rate must be < 1.0 (got {lr!r}); values that large always diverge training"
)
return lr
class TrainingStartRequest(BaseModel):
"""Request schema for starting training"""
model_name: str = Field(
..., description = "Model identifier (e.g., 'unsloth/llama-3-8b-bnb-4bit')"
)
project_name: Optional[str] = Field(
None,
max_length = 80,
description = "Optional user-defined project name appended to run folders and shown in history",
)
start_request_id: Optional[str] = Field(
None,View on GitHub (pinned to 203007d190)
Solutions
- Use a realistic LR in the 1e-6..1e-3 range; anything >= 1.0 will diverge.
- If the number came from a config in different units, convert (e.g. per-mille 2 → 0.002).
- Clamp slider/programmatic LR values in the client with min(max(lr, 1e-7), 1e-2).
Example fix
// before
body = { ..., learning_rate: 2 } // meant 2e-3
// after
body = { ..., learning_rate: 2e-3 } Defensive patterns
Strategy: validation
Validate before calling
MAX_LR = 1.0
def lr_under_cap(body: dict) -> bool:
try:
return float(body.get("learning_rate")) < MAX_LR
except (TypeError, ValueError):
return False Type guard
function lrUnderCap(v: number): boolean {
return v < 1.0;
} Prevention
- Clamp LR sliders to 1e-7..1e-2
- Double-check units when copying LRs from papers
- Typical fine-tuning range is 1e-6..1e-3
When it happens
Trigger: POST a training start request with "learning_rate": 1.0, 1, 5e-3 is fine but 5.0 is not — any parsed float >= 1.0, including the string "1.0" and the boolean-free integer 1.
Common situations: Unit confusion (per-100 vs per-unit schedules); AdamW-style LR copied from a paper using LR=1.0 for specific architectures; accidentally sending a percentage (e.g. 100 meaning 100%); slider UIs allowing values above 1.0 without clamping.
Related errors
- learning_rate is required
- learning_rate must be parseable as float (got {v!r})
- learning_rate must be > 0 (got {lr!r}); typical range is 1e-
- learning_rate must be a number, got {self.learning_rate!r}
- learning_rate must be > 0
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/e58f026eb4effe06.
Report an issue: GitHub.