{"record":{"id":"bf3b2c90612843bb","repo":"unslothai/unsloth","slug":"unsloth-mlx-max-grad-leaf-norm-max-grad-leaf-nor","errorCode":null,"errorMessage":"Unsloth MLX: max_grad_leaf_norm={max_grad_leaf_norm} must be finite and >= 0 (0 or None disables proportional leaf-norm clipping).","messagePattern":"Unsloth MLX: max_grad_leaf_norm=(.+?) must be finite and >= 0 \\(0 or None disables proportional leaf-norm clipping\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/worker.py","lineNumber":3022,"sourceCode":"        eval_steps_val = max(1, int(eval_steps_value * max_steps))\n    else:\n        eval_steps_val = int(eval_steps_value)\n\n    # Re-validate for direct worker callers; training.py normalizes the main path.\n    max_grad_norm = _resolve_mlx_max_grad_norm(config.get(\"max_grad_norm\"))\n    max_grad_value = config.get(\"max_grad_value\")\n    if max_grad_value is not None:\n        max_grad_value = float(max_grad_value)\n        if max_grad_value < 0 or not math.isfinite(max_grad_value):\n            raise ValueError(\n                f\"Unsloth MLX: max_grad_value={max_grad_value} must be finite and >= 0 \"\n                \"(0 or None disables elementwise clipping).\"\n            )\n    max_grad_leaf_norm = config.get(\"max_grad_leaf_norm\")\n    if max_grad_leaf_norm is not None:\n        max_grad_leaf_norm = float(max_grad_leaf_norm)\n        if max_grad_leaf_norm < 0 or not math.isfinite(max_grad_leaf_norm):\n            raise ValueError(\n                f\"Unsloth MLX: max_grad_leaf_norm={max_grad_leaf_norm} must be finite and >= 0 \"\n                \"(0 or None disables proportional leaf-norm clipping).\"\n            )\n    weight_decay = config.get(\"weight_decay\", 0.001)\n    weight_decay = 0.001 if weight_decay is None else float(weight_decay)\n\n    mlx_config_kwargs = dict(\n        per_device_train_batch_size = batch_size,\n        gradient_accumulation_steps = grad_accum,\n        max_steps = max_steps,\n        learning_rate = lr_value,\n        warmup_steps = warmup_steps,\n        lr_scheduler_type = lr_scheduler_type,\n        optim = optim_name,\n        weight_decay = weight_decay,\n        max_grad_norm = max_grad_norm,\n        max_grad_value = max_grad_value,\n        logging_steps = 1,","sourceCodeStart":3004,"sourceCodeEnd":3040,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/worker.py#L3004-L3040","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nconfig = {\"max_grad_leaf_norm\": float(\"nan\")}\n\n# after\nimport math\nvalue = config.get(\"max_grad_leaf_norm\")\nconfig[\"max_grad_leaf_norm\"] = value if (value is not None and math.isfinite(value) and value >= 0) else None","handlingStrategy":"validation","validationCode":"import math\n\nvalue = config.get(\"max_grad_leaf_norm\")\nif value is not None and (not isinstance(value, (int, float)) or not math.isfinite(value) or value < 0):\n    config[\"max_grad_leaf_norm\"] = None","typeGuard":"def is_valid_max_grad_leaf_norm(v) -> bool:\n    return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) and v >= 0)","tryCatchPattern":"try:\n    run_training(config)\nexcept ValueError as e:\n    if \"max_grad_leaf_norm\" in str(e):\n        config[\"max_grad_leaf_norm\"] = None\n        run_training(config)\n    else:\n        raise","preventionTips":["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."],"tags":["training","mlx","config-validation","gradient-clipping"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}