unslothai/unsloth · error · ValueError
Unsloth MLX: max_grad_leaf_norm={max_grad_leaf_norm} must be
Error message
Unsloth MLX: max_grad_leaf_norm={max_grad_leaf_norm} must be finite and >= 0 (0 or None disables proportional leaf-norm clipping). What it means
Raised by the Unsloth MLX training worker when config['max_grad_leaf_norm'] is negative or non-finite. This setting controls proportional leaf-norm gradient clipping in the MLX trainer; 0 or None disables it, and any other value must be a finite float >= 0. Like max_grad_value it is re-validated in the worker because direct worker callers bypass training.py's normalization.
Source
Thrown at studio/backend/core/training/worker.py:3022
eval_steps_val = max(1, int(eval_steps_value * max_steps))
else:
eval_steps_val = int(eval_steps_value)
# Re-validate for direct worker callers; training.py normalizes the main path.
max_grad_norm = _resolve_mlx_max_grad_norm(config.get("max_grad_norm"))
max_grad_value = config.get("max_grad_value")
if max_grad_value is not None:
max_grad_value = float(max_grad_value)
if max_grad_value < 0 or not math.isfinite(max_grad_value):
raise ValueError(
f"Unsloth MLX: max_grad_value={max_grad_value} must be finite and >= 0 "
"(0 or None disables elementwise clipping)."
)
max_grad_leaf_norm = config.get("max_grad_leaf_norm")
if max_grad_leaf_norm is not None:
max_grad_leaf_norm = float(max_grad_leaf_norm)
if max_grad_leaf_norm < 0 or not math.isfinite(max_grad_leaf_norm):
raise ValueError(
f"Unsloth MLX: max_grad_leaf_norm={max_grad_leaf_norm} must be finite and >= 0 "
"(0 or None disables proportional leaf-norm clipping)."
)
weight_decay = config.get("weight_decay", 0.001)
weight_decay = 0.001 if weight_decay is None else float(weight_decay)
mlx_config_kwargs = dict(
per_device_train_batch_size = batch_size,
gradient_accumulation_steps = grad_accum,
max_steps = max_steps,
learning_rate = lr_value,
warmup_steps = warmup_steps,
lr_scheduler_type = lr_scheduler_type,
optim = optim_name,
weight_decay = weight_decay,
max_grad_norm = max_grad_norm,
max_grad_value = max_grad_value,
logging_steps = 1,View on GitHub (pinned to 203007d190)
Solutions
- Set max_grad_leaf_norm to 0 or omit it (None) to disable proportional leaf-norm clipping, or use a finite positive float such as 1.0.
- Validate/normalize the value at the config boundary (API/UI) before it reaches the worker.
- Audit the config source for NaN/negative sentinels if the value is computed.
Example fix
# before
config = {"max_grad_leaf_norm": float("nan")}
# after
import math
value = config.get("max_grad_leaf_norm")
config["max_grad_leaf_norm"] = value if (value is not None and math.isfinite(value) and value >= 0) else None Defensive patterns
Strategy: validation
Validate before calling
import math
value = config.get("max_grad_leaf_norm")
if value is not None and (not isinstance(value, (int, float)) or not math.isfinite(value) or value < 0):
config["max_grad_leaf_norm"] = None Type guard
def is_valid_max_grad_leaf_norm(v) -> bool:
return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) and v >= 0) Try / catch
try:
run_training(config)
except ValueError as e:
if "max_grad_leaf_norm" in str(e):
config["max_grad_leaf_norm"] = None
run_training(config)
else:
raise Prevention
- Centralize clipping-parameter normalization in one helper used by both the API layer and the worker.
- Treat None as the only 'disabled' sentinel for gradient clipping options.
- Add unit tests asserting NaN and negative values are rejected before dispatch.
When it happens
Trigger: Calling the MLX training worker with config['max_grad_leaf_norm'] set to a negative number, NaN, or +/-inf. Finite positive values, 0, and None pass validation.
Common situations: Copying a config from another trainer where -1 means 'disabled'; NaN leaking in from a YAML .nan entry or a divide-by-zero in a sweep; a frontend sending an unvalidated numeric input.
Related errors
- Unsloth MLX: max_grad_value={max_grad_value} must be finite
- dataset_streaming is not yet supported on Apple Silicon (MLX
- '{family_name}' needs diffusers ({pipeline_class}), which th
- '{family_name}' needs diffusers ({pipeline_class}), but this
- Unsloth MLX: use_adapter must be None, True, False, or a str
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/bf3b2c90612843bb.
Report an issue: GitHub.