{"record":{"id":"ce2a8ecd879d83c7","repo":"unslothai/unsloth","slug":"dataset-slice-end-must-be-greater-than-or-equal-to","errorCode":null,"errorMessage":"dataset_slice_end must be greater than or equal to dataset_slice_start","messagePattern":"dataset_slice_end must be greater than or equal to dataset_slice_start","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"studio/backend/models/training.py","lineNumber":219,"sourceCode":"            values.setdefault(\"train_split\", values.pop(\"split\"))\n        return values\n\n    @field_validator(\"project_name\")\n    @classmethod\n    def _normalize_project_name(cls, value: Optional[str]) -> Optional[str]:\n        return normalize_project_name(value)\n\n    # NOTE: pydantic runs all `mode=\"after\"` validators in definition order, and\n    # `_check_steps_or_epochs` is lower in this class; keep these checks order-independent.\n    @model_validator(mode = \"after\")\n    def _validate_dataset_slice(self) -> \"TrainingStartRequest\":\n        # start == end is intentionally allowed (a deliberate single-row slice); the trainer warns.\n        if (\n            self.dataset_slice_start is not None\n            and self.dataset_slice_end is not None\n            and self.dataset_slice_end < self.dataset_slice_start\n        ):\n            raise ValueError(\n                \"dataset_slice_end must be greater than or equal to dataset_slice_start\"\n            )\n        return self\n\n    @field_validator(\"hf_dataset\")\n    @classmethod\n    def _check_hf_dataset(cls, v: Optional[str]) -> Optional[str]:\n        if v is None:\n            return v\n        v = v.strip()\n        if not v:\n            return None\n        if len(v) > 256:\n            raise ValueError(\"hf_dataset is too long (max 256 chars)\")\n        if \"..\" in v:\n            raise ValueError(\"hf_dataset must not contain '..'\")\n        if any(_HF_DATASET_ID_SEGMENT_RE.fullmatch(segment) is None for segment in v.split(\"/\")):\n            raise ValueError(\"hf_dataset contains invalid characters or path segments\")","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/training.py#L201-L237","documentation":"Raised by the _validate_dataset_slice model_validator on TrainingStartRequest. The optional dataset_slice_start/dataset_slice_end pair defines a row range of the dataset to train on; the validator enforces end >= start so the slice is never negative-length. start == end is deliberately allowed (a single-row slice) — the trainer warns but proceeds. The validator comment notes it is written to be order-independent relative to _check_steps_or_epochs.","triggerScenarios":"POST a training start request with e.g. dataset_slice_start=100 and dataset_slice_end=50, or defaults where start is user-supplied but end is a hard-coded smaller constant.","commonSituations":"UI two-number inputs where users can type start > end; paging logic that computes end as start - limit by an off-by-one; resuming a job with a stale slice_end from a shorter dataset; percentage-to-row conversions that produce inverted bounds.","solutions":["Make sure dataset_slice_end >= dataset_slice_start; for 'last N rows' semantics use start = total - N, end = total.","Swap or clamp the pair client-side when the user inverts them.","Remember start == end is valid (single-row slice) if that is the intent."],"exampleFix":"// before\n{ dataset_slice_start: 100, dataset_slice_end: 50 }\n// after\n{ dataset_slice_start: 50, dataset_slice_end: 100 }","handlingStrategy":"validation","validationCode":"def slice_ordered(body: dict) -> bool:\n    s, e = body.get(\"dataset_slice_start\"), body.get(\"dataset_slice_end\")\n    return s is None or e is None or e >= s","typeGuard":"function sliceOrdered(s?: number | null, e?: number | null): boolean {\n  return s == null || e == null || e >= s;\n}","tryCatchPattern":null,"preventionTips":["Use a range picker that enforces min<=max in the UI","Compute end as start + length, never start - length","Remember start == end is legal (single-row slice)"],"tags":["pydantic","validation","training","dataset","off-by-one"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}