{"record":{"id":"ff0feb6b15995e8a","repo":"unslothai/unsloth","slug":"learning-rate-is-required","errorCode":null,"errorMessage":"learning_rate is required","messagePattern":"learning_rate is required","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"studio/backend/models/training.py","lineNumber":85,"sourceCode":"        alias = \"useIamRole\",\n        description = \"Use IAM role credentials instead of access keys\",\n    )\n\n    @model_validator(mode = \"after\")\n    def _check_credentials(self) -> \"S3Config\":\n        # Require either IAM role auth or a full key pair so credentials are never half-configured.\n        if not self.use_iam_role and not (self.access_key_id and self.secret_access_key):\n            raise ValueError(\n                \"s3_config requires either use_iam_role=True or both \"\n                \"access_key_id and secret_access_key\"\n            )\n        return self\n\n\ndef _parse_lr(v: Any) -> float:\n    \"\"\"Parse learning_rate as a positive float strictly below _MAX_LR_VALUE.\"\"\"\n    if v is None:\n        raise ValueError(\"learning_rate is required\")\n    if isinstance(v, bool):\n        raise ValueError(\"learning_rate must be a number, not a bool\")\n    try:\n        lr = float(v)\n    except (TypeError, ValueError):\n        raise ValueError(f\"learning_rate must be parseable as float (got {v!r})\")\n    if not (lr > 0.0):\n        raise ValueError(f\"learning_rate must be > 0 (got {lr!r}); typical range is 1e-6 .. 1e-3\")\n    if lr >= _MAX_LR_VALUE:\n        raise ValueError(\n            f\"learning_rate must be < 1.0 (got {lr!r}); values that large always diverge training\"\n        )\n    return lr\n\n\nclass TrainingStartRequest(BaseModel):\n    \"\"\"Request schema for starting training\"\"\"\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/training.py#L67-L103","documentation":"Raised by the _parse_lr field parser used for learning_rate in TrainingStartRequest. learning_rate has no default, so passing None (or omitting it when the client schema does not mark it optional) reaches the parser and fails immediately with this dedicated message rather than a generic 'field required' error. The parser also rejects bools, non-numeric values, non-positive values, and values >= 1.0 in subsequent checks.","triggerScenarios":"POST a training start request with \"learning_rate\": null, or a request body that omits learning_rate where the client-side serializer explicitly sends null (common when a typed client has learning_rate?: number).","commonSituations":"A form/UI where the LR field is optional and submits null when blank; copying a config template that used a scheduler to derive LR; migrating from an API version where learning_rate had a default; JSON serializers that emit null for unset optional fields.","solutions":["Set an explicit learning_rate in the request; typical values are 1e-6 to 1e-3 (e.g. 2e-5 for LoRA fine-tuning).","Make the field required in your client schema so nulls cannot be serialized.","If the LR should come from a preset/config file, ensure that file actually contains the key before building the request."],"exampleFix":"// before\nbody = { model_name, hf_dataset, learning_rate: form.lr } // form.lr is null\n// after\nbody = { model_name, hf_dataset, learning_rate: form.lr ?? 2e-5 }","handlingStrategy":"validation","validationCode":"def has_learning_rate(body: dict) -> bool:\n    return body.get(\"learning_rate\") is not None","typeGuard":"function hasLr(body: { learning_rate?: number | null }): boolean {\n  return typeof body.learning_rate === 'number';\n}","tryCatchPattern":null,"preventionTips":["Make learning_rate a required number in client types","Default blank UI fields to a sane value (2e-5) instead of null","Reject null in the request builder"],"tags":["pydantic","validation","training","hyperparameters"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}