hiyouga/LlamaFactory · error · ValueError
No valid messages or chosen_messages/rejected_messages found
Error message
No valid messages or chosen_messages/rejected_messages found in sample.
What it means
The renderer's batch path looks for 'messages' (plain SFT/generation) or 'chosen_messages'/'rejected_messages' (preference pairs like DPO/KTO) in each sample. If none are present the sample has no renderable content and a ValueError is raised instead of silently emitting an empty batch.
Source
Thrown at src/llamafactory/v1/core/rendering/rendering.py:313
# chosen and rejected are independent sequences; position ids must restart at 1 for
# each (a single continuous range would offset rejected's positional embeddings).
model_input["position_ids"] = list(range(1, len(chosen_input["input_ids"]) + 1)) + list(
range(1, len(rejected_input["input_ids"]) + 1)
)
for key in _MULTIMODAL_PASSTHROUGH_KEYS:
tensors = [inp[key] for inp in (chosen_input, rejected_input) if key in inp]
if tensors:
model_input[key] = torch.cat(tensors, dim=0)
if "mm_token_type_ids" in chosen_input or "mm_token_type_ids" in rejected_input:
chosen_mm = chosen_input.get("mm_token_type_ids", [0] * len(chosen_input["input_ids"]))
rejected_mm = rejected_input.get("mm_token_type_ids", [0] * len(rejected_input["input_ids"]))
model_input["mm_token_type_ids"] = chosen_mm + rejected_mm
rendered.append(model_input)
else:
raise ValueError("No valid messages or chosen_messages/rejected_messages found in sample.")
for model_input in rendered:
if "extra_info" in sample:
model_input["extra_info"] = sample["extra_info"]
if "_dataset_name" in sample:
model_input["_dataset_name"] = sample["_dataset_name"]
model_inputs.append(model_input)
return model_inputs
View on GitHub (pinned to f28afaf635)
Solutions
- Rename/emit the expected key: 'messages' for standard samples, or both 'chosen_messages' and 'rejected_messages' for preference samples
- Filter malformed samples during preprocessing: keep only samples containing at least one of the accepted key sets
- If your data is pre-tokenized, bypass this renderer path rather than feeding token ids as messages
Example fix
# before
sample = {"conversation": [{"role": "user", "content": "hi"}, ...]}
# after
sample = {"messages": [{"role": "user", "content": "hi"}, ...]} Defensive patterns
Strategy: validation
Validate before calling
def sample_is_renderable(sample: dict) -> bool:
return "messages" in sample or ("chosen_messages" in sample and "rejected_messages" in sample) Type guard
def is_renderable_sample(sample: dict) -> bool:
return (
isinstance(sample, dict)
and ("messages" in sample
or ("chosen_messages" in sample and "rejected_messages" in sample))
) Prevention
- Emit 'messages' (or both chosen_messages and rejected_messages) from custom converters
- Filter datasets with sample_is_renderable before training to fail with row context
When it happens
Trigger: Passing a dataset of samples that only contain pre-tokenized fields (input_ids), raw 'conversations'/'messages' under a different key name, or a preference sample with only one of chosen/rejected; an empty dict sample.
Common situations: Custom dataset converters that keep the original column name ('conversation', 'chat', 'history') instead of the expected keys; mixed-format datasets where some rows lack the fields.
Related errors
- Cannot find valid samples, check `data/README.md` for the da
- tool_call value is not valid JSON: {content['value']!r}
- {kind} placeholder count ({seen}) != number of {kind} blocks
- DPO training requires pair-format samples containing chosen/
- RM training requires pair-format samples containing chosen/r
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/846669722e75f5d5.
Report an issue: GitHub.