unslothai/unsloth · error · ValueError

learning_rate is required

Error message

learning_rate is required

What it means

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.

Source

Thrown at studio/backend/models/training.py:85

        alias = "useIamRole",
        description = "Use IAM role credentials instead of access keys",
    )

    @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"""

View on GitHub (pinned to 203007d190)

Solutions

  1. Set an explicit learning_rate in the request; typical values are 1e-6 to 1e-3 (e.g. 2e-5 for LoRA fine-tuning).
  2. Make the field required in your client schema so nulls cannot be serialized.
  3. If the LR should come from a preset/config file, ensure that file actually contains the key before building the request.

Example fix

// before
body = { model_name, hf_dataset, learning_rate: form.lr } // form.lr is null
// after
body = { model_name, hf_dataset, learning_rate: form.lr ?? 2e-5 }
Defensive patterns

Strategy: validation

Validate before calling

def has_learning_rate(body: dict) -> bool:
    return body.get("learning_rate") is not None

Type guard

function hasLr(body: { learning_rate?: number | null }): boolean {
  return typeof body.learning_rate === 'number';
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/ff0feb6b15995e8a. Report an issue: GitHub.