unslothai/unsloth · error · ValueError
learning_rate must be > 0 (got {lr!r}); typical range is 1e-
Error message
learning_rate must be > 0 (got {lr!r}); typical range is 1e-6 .. 1e-3 What it means
Raised by the _parse_lr parser when the parsed learning rate is not strictly positive (zero or negative, including -0.0 and NaN comparisons falling through). A zero or negative LR makes no training progress or diverges immediately, so it is rejected at request validation time. The message suggests the typical range 1e-6 .. 1e-3.
Source
Thrown at studio/backend/models/training.py:93
raise ValueError(
"s3_config requires either use_iam_role=True or both "
"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",
)View on GitHub (pinned to 203007d190)
Solutions
- Send a positive learning rate; start with 2e-5 for LoRA or 1e-4..1e-3 for full fine-tuning and tune from there.
- If computing LR from a schedule, clamp the first warmup step to a small positive epsilon or start the request at step 1.
- Check sign/unit conversions in whatever computes the value.
Example fix
# before (warmup step 0 -> lr 0)
lr = base_lr * (step / warmup_steps)
body = {"learning_rate": lr}
# after
lr = max(base_lr * (step / warmup_steps), 1e-7)
body = {"learning_rate": lr} Defensive patterns
Strategy: validation
Validate before calling
def lr_positive(body: dict) -> bool:
v = body.get("learning_rate")
try:
return float(v) > 0.0
except (TypeError, ValueError):
return False Type guard
function lrPositive(v: number): boolean {
return v > 0;
} Prevention
- Clamp warmup schedules to a positive epsilon at step 0
- Initialize numeric form fields to 2e-5, never 0
When it happens
Trigger: POST a training start request with "learning_rate": 0, -1e-5, "0.0", or a computed value that underflows to 0 (e.g. a warmup step 0 of a schedule multiplied by base LR).
Common situations: Warmup schedules that start at step 0 producing LR=0; subtracting constants from LR in adaptive logic; sign errors when converting units; default-initializing a numeric field to 0 in a form or proto.
Related errors
- learning_rate is required
- learning_rate must be parseable as float (got {v!r})
- learning_rate must be < 1.0 (got {lr!r}); values that large
- 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/fb8c6410eac01ac5.
Report an issue: GitHub.