{"record":{"id":"84f3f6b1c0161dd8","repo":"unslothai/unsloth","slug":"unsloth-mlx-max-grad-value-max-grad-value-must","errorCode":null,"errorMessage":"Unsloth MLX: max_grad_value={max_grad_value} must be finite and >= 0 (0 or None disables elementwise clipping).","messagePattern":"Unsloth MLX: max_grad_value=(.+?) must be finite and >= 0 \\(0 or None disables elementwise clipping\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/worker.py","lineNumber":3014,"sourceCode":"\n    # ── 6. Create trainer ──\n    raw_eval_steps = config.get(\"eval_steps\", 0)\n    if evaluation_enabled(raw_eval_steps):\n        eval_steps_value = float(raw_eval_steps)\n    else:\n        eval_steps_value = 0.0\n    if 0 < eval_steps_value < 1:\n        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,","sourceCodeStart":2996,"sourceCodeEnd":3032,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/worker.py#L2996-L3032","documentation":"Raised by the Unsloth MLX training worker when the config value max_grad_value is negative or non-finite (NaN or +/-inf). max_grad_value controls elementwise gradient clipping in the MLX trainer; 0 or None disables it, so any other value must be a finite float >= 0. This is a re-validation in the worker because the worker can be called directly, bypassing the normalization that training.py performs on the main path.","triggerScenarios":"Calling the MLX training worker with config['max_grad_value'] set to a negative number, NaN, or inf (e.g. from a math expression that overflowed, a string parsed later, or -1 used as a 'disable' sentinel). Passing 0 or None does NOT trigger it; passing a finite positive float does not either.","commonSituations":"Users copy a PyTorch-style config where -1 or 1e9 means 'off'; a UI/API forwards an empty string that converts to NaN; a YAML config has .nan or .inf; hyperparameter sweeps generate out-of-range values.","solutions":["Set max_grad_value to 0 or remove it (None) if you want elementwise clipping disabled, or to a finite positive float like 1.0.","If you call the worker directly, normalize the value before dispatch (mirror what training.py does) so NaN/negative sentinels are converted to None.","Check the upstream config source (UI, YAML, API payload) for NaN-inducing values such as .nan, float('inf'), or -1 sentinels and fix them there."],"exampleFix":"# before\nconfig = {\"max_grad_value\": -1}  # raises ValueError\n\n# after\nconfig = {\"max_grad_value\": None}  # disables elementwise clipping","handlingStrategy":"validation","validationCode":"import math\n\ndef valid_max_grad_value(value):\n    return value is None or (isinstance(value, (int, float)) and math.isfinite(value) and value >= 0)\n\nif not valid_max_grad_value(config.get(\"max_grad_value\")):\n    config[\"max_grad_value\"] = None  # or raise your own clearer error early","typeGuard":"def is_valid_max_grad_value(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_value\" in str(e):\n        config[\"max_grad_value\"] = None\n        run_training(config)\n    else:\n        raise","preventionTips":["Validate numeric hyperparameters at the API/UI boundary before they reach the training worker.","Never use -1 or 1e9 as an 'off' sentinel for clipping fields; use None or 0.","Reject NaN/inf early wherever config values are computed (sweeps, YAML loads)."],"tags":["training","mlx","config-validation","gradient-clipping"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}