Skip to main content
A dataset is a collection of training examples Veri reads at job submission time. Three ways to get one in:
  1. Upload a JSONL file directly
  2. Connect a Hugging Face dataset — Veri pulls from the Hub
  3. Create a dataset stream: an append-only dataset that grows as data arrives; training pins immutable snapshots (name@latest, name@snap-N)
Either way, the result is a dataset record with an id you reference in client.training_jobs.create(dataset_id=...). This page covers the one-shot sources (upload, Hugging Face); streams have their own page.

JSONL format

Each line is one training example, and the fields depend on the training method. A GRPO row has a prompt:
  • prompt: a string or a list of OpenAI-format message dicts
  • answer: ground truth used by your reward function (optional but typically present). The column name is passed to your reward as a keyword argument of the same name, so it must match what the function reads. Every example here uses answer; if you map it to another name, read that name instead.
SFT rows carry messages (chat), text, or prompt + completion. DPO rows carry chosen + rejected, with an optional prompt, as all strings or all message lists (one shape per row and dataset). The ShareGPT and Alpaca shapes in Supported formats upload too. Upload rejects a row that has none of prompt, messages, text, chosen + rejected, conversations, or instruction + output. The dataset’s format records the shape of its first row: prompt, completion, preference, chat (chat rows that also carry a prompt), chat_no_prompt (chat rows without one), text, alpaca, sharegpt, or eval. When you submit a job, Veri checks that format against the method and rejects a clear mismatch with a 400 that names the fields the method needs. For example: GRPO on chat_no_prompt, text, alpaca or sharegpt rows (GRPO generates from a prompt, so add a prompt column), sft_text on prompt-only rows, or dpo on prompt-completion rows. Datasets with no recorded format (Hugging Face sources) and any other row the trainer can’t use fail with dataset_format_incompatible at the start of the job.

Source types

Connect from Hugging Face

Most users start here — pull openai/gsm8k straight from HF, no local download. The column_mapping tells Veri which source columns become prompt and answer.
Private and gated Hugging Face datasets are not supported yet; connect public datasets, or upload the data directly.

Supported formats

Veri detects the dataset’s format from its columns and converts it to the shape the trainer expects, so you can connect community datasets as they are: Datasets that don’t match any of these formats, or use tool-calling roles (observation, function_call), are rejected with a dataset_format_incompatible error at the start of the job rather than trained on incorrectly. Use column_mapping to rename columns into one of the shapes above. Detection and conversion run in the open-source runtime — see detect_dataset_format and normalize_rows in training_runtime.py to check exactly what your dataset passed through. Each method still needs the right shape: SFT trains on text, messages, or prompt-completion rows; GRPO needs a prompt column; DPO needs chosen and rejected.

Snapshot caching

The first training job on a connected HF dataset downloads it from the Hub, converts it, and caches the result. Later jobs on the same dataset read the cache directly: faster starts, and your data can’t change mid-experiment if the upstream dataset is edited. To pick up upstream changes, connect the dataset again under a new name.

Upload a JSONL file

For one-off experiments:
The CLI runs structural validation by default (every row must carry one of the fields above). Pass --skip-validation to skip it. --deep-check (tokenizer-aware checks) is reserved and not implemented yet: it only prints a notice.

Dedup

Datasets are content-addressed. Uploading the same bytes twice (same file, or two files with identical content) returns the same id: one S3 object, one DB row. The existing record keeps its original name, even if the second upload passed a different one. This means you can re-run a script that uploads the same dataset without worrying about stale duplicates.

Preview rows

Click a dataset on the dashboard’s Datasets page to open a row viewer that pages through the stored JSONL 50 rows at a time, so large datasets never download in full. The row number in the footer is editable: type a row number and press Enter to jump straight there (the first jump into a large dataset builds a small row index, so it can take a moment; later jumps are instant). Uploaded datasets are previewable immediately. Connected Hugging Face datasets become previewable after their first training run creates the snapshot. The same paging is available programmatically via GET /v1/datasets/{dataset_id}/rows, with cursor for sequential pages or start_row to jump to an absolute row.

Lifecycle

Datasets persist until you delete them, either from the dashboard or via DELETE /v1/datasets/{dataset_id}. Deletion is blocked while an active training job still references the dataset. Deletion is also refused (409, naming the experiments) while an experiment is pinned to one of the dataset’s snapshots.

Name conflicts

Connecting a dataset under a name that already exists returns the existing dataset (200, same id) when the source matches: the same source_type and huggingface_dataset. A different source under that name is a 409 with {"error": {"message": "Dataset '...' already exists with a different configuration. ..."}}. Only the source is compared, not huggingface_config: connecting the same Hugging Face repo under the same name with a different split, subset or column_mapping silently returns the existing dataset with its original configuration. Use a new name when you change them.

Where to go next

Reward functions

Write TRL-format functions and attach them to jobs inline.

Submit a training job

Use your dataset_id in training_jobs.create.

Quickstart

Full GRPO end-to-end with GSM8K.

SFT with Unsloth demo

Run Unsloth’s Qwen3 QLoRA recipe as a managed SFT job.