unslothai/unsloth · error · ValueError
learning_rate must be a number, not a bool
Error message
learning_rate must be a number, not a bool
What it means
Raised by the _parse_lr parser: in Python, bool is a subclass of int, so True/False would otherwise parse as float 1.0/0.0 and slip through numeric validation. The parser explicitly rejects bools before the float() conversion so that a boolean is never silently coerced into a learning rate (1.0 would also be caught by the < 1.0 cap, but False would parse as 0.0 and only fail the > 0 check with a misleading message).
Source
Thrown at studio/backend/models/training.py:87
)
@model_validator(mode = "after")
def _check_credentials(self) -> "S3Config":
# Require either IAM role auth or a full key pair so credentials are never half-configured.
if not self.use_iam_role and not (self.access_key_id and self.secret_access_key):
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')"View on GitHub (pinned to 203007d190)
Solutions
- Replace the boolean with a real numeric learning rate, e.g. 2e-5.
- If YAML is the source, quote the value (learning_rate: "2e-5") to avoid YAML 1.1 truthy parsing of yes/no/on/off.
- Add a client-side typeof check (number, not boolean) before submitting.
Example fix
# config.yaml before learning_rate: yes # YAML parses as boolean True # after learning_rate: 2.0e-05
Defensive patterns
Strategy: type-guard
Validate before calling
def lr_is_numeric(body: dict) -> bool:
return not isinstance(body.get("learning_rate"), bool) Type guard
function isNumberNotBool(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v);
} Prevention
- Quote YAML learning_rate values
- Never bind a boolean/flag input to the LR field
- Add a schema check (typeof number) in the request builder
When it happens
Trigger: POST a training start request with "learning_rate": true or "learning_rate": false — e.g. a YAML/JSON config where the LR was templated from a flag, or a UI checkbox bound to the wrong field.
Common situations: Config templating (Helm/Jinja) that renders a boolean into a numeric slot; YAML configs where `learning_rate: yes` parses as boolean true; feature-flag lookups accidentally wired to the LR field; dynamically built request dicts with wrong keys.
Related errors
- save_steps / save_total_limit must be whole numbers, got {se
- ema_decay must be a number, got {self.ema_decay!r}
- s3_config requires either use_iam_role=True or both access_k
- learning_rate is required
- learning_rate must be parseable as float (got {v!r})
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/5804e5b8faae4e12.
Report an issue: GitHub.