unslothai/unsloth · error · ValueError
dataset_streaming requires a plain split name in {field_name
Error message
dataset_streaming requires a plain split name in {field_name} (got {split_val!r}); use a name such as 'train' or 'validation'. What it means
Pydantic model validator on TrainingStartRequest that runs when dataset_streaming is true. Streaming mode in HuggingFace load_dataset does not accept slice syntax (e.g. 'train[:100]' or 'train+test'), so the request is rejected early with a clear message instead of failing later inside the datasets library with 'ValueError: Bad split'. Only plain split names such as 'train' or 'validation' are accepted for train_split and eval_split.
Source
Thrown at studio/backend/models/training.py:593
)
@field_validator("target_modules", mode = "before")
@classmethod
def _normalize_target_modules(cls, value: Any) -> Any:
# Sanitized non-LoRA history stores the unused value as null; treat it as an omitted list.
return [] if value is None else value
@model_validator(mode = "after")
def _validate_streaming_splits(self) -> "TrainingStartRequest":
# Streaming load_dataset does not accept HF slice syntax (probe-confirmed: ValueError: Bad
# split). Reject early with a clear message so the user knows to use a plain split name.
if self.dataset_streaming:
for field_name, split_val in (
("train_split", self.train_split),
("eval_split", self.eval_split),
):
if split_val is not None and not valid_hf_dataset_split_name(split_val):
raise ValueError(
f"dataset_streaming requires a plain split name in {field_name} "
f"(got {split_val!r}); use a name such as 'train' or 'validation'."
)
return self
@model_validator(mode = "after")
def _check_steps_or_epochs(self) -> "TrainingStartRequest":
# Each accepts 0 as "use the other"; both 0 means nothing to train.
if (self.max_steps is None or self.max_steps == 0) and self.num_epochs == 0:
raise ValueError("Either num_epochs or max_steps must be > 0; both cannot be 0.")
return self
@model_validator(mode = "after")
def _validate_lora_variant_flags(self) -> "TrainingStartRequest":
# The frontend only ever sends one of these and never under Full Finetuning, but a direct
# API/YAML/CLI caller can bypass that. Nothing downstream breaks, but reject early for a
# clear error instead of a silently-ignored flag.
active = [View on GitHub (pinned to 203007d190)
Solutions
- Set train_split/eval_split to plain split names like 'train' and 'validation' when dataset_streaming is true.
- If you need a subset, disable streaming and keep the slice syntax, since non-streaming load_dataset accepts it.
- If a smaller streamed dataset is required, take only the first N examples in the training loop (e.g. itertools.islice over the iterable dataset) instead of encoding it in the split name.
Example fix
# before req = TrainingStartRequest(dataset_streaming=True, train_split="train[:100]", ...) # after req = TrainingStartRequest(dataset_streaming=True, train_split="train", ...)
Defensive patterns
Strategy: validation
Validate before calling
import re
def is_plain_split(name: str) -> bool:
# HF split names are alphanumeric/underscore/dash; slice syntax adds [ ] + % :
return bool(re.fullmatch(r"[A-Za-z0-9_-]+", name))
def check_streaming_splits(payload: dict) -> list[str]:
errs = []
if payload.get("dataset_streaming"):
for f in ("train_split", "eval_split"):
v = payload.get(f)
if v is not None and not is_plain_split(v):
errs.append(f"{f}={v!r} is not a plain split name")
return errs Prevention
- Keep split names free of '[', ']', '+', '%' whenever dataset_streaming is true.
- Centralize split-name construction in one helper so streaming and non-streaming paths cannot diverge.
- Add a client-side unit test asserting streaming payloads only contain plain names.
When it happens
Trigger: POSTing a TrainingStartRequest with dataset_streaming=true and train_split='train[:500]' or eval_split='train+validation'; also any slice/percentage syntax ('train[:10%]') or a combined-split expression. Trigger occurs at Pydantic validation time, before any dataset loading starts.
Common situations: Copying a split value from a non-streaming config where slicing worked fine; downsampling large datasets via slice syntax when switching to streaming; scripts that programmatically build split names with [:N] suffixes.
Related errors
- dataset_streaming streams from the Hub and cannot use the lo
- scan_dataset requires a materialized Dataset, not an Iterabl
- hf_dataset is too long (max 256 chars)
- hf_dataset contains invalid characters or path segments
- subset is too long (max {MAX_HF_DATASET_OPTION_LENGTH} chars
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/2c98d4caa475a9ca.
Report an issue: GitHub.