hiyouga/LlamaFactory · error · ValueError

Drop last must be True.

Error message

Drop last must be True.

What it means

The v1 batching scheduler is built around StatefulDistributedSampler with drop_last semantics: every batch must be exactly global_batch_size so checkpoint-resumable step accounting stays exact. drop_last=False would produce a ragged final batch and break stateful resume, so it is rejected outright rather than silently supported.

Source

Thrown at src/llamafactory/v1/core/utils/batching.py:198

        self.drop_last = drop_last
        self.seed = seed
        self._warned_truncation = False  # warn once when dropping fully-truncated (zero-loss) samples
        # TODO: support length and infinity
        dp_size = DistributedInterface().get_world_size(Dim.DP)

        if self.global_batch_size is None:
            self.global_batch_size = dp_size * micro_batch_size
            self.num_micro_batch = 1
        elif self.global_batch_size % (dp_size * micro_batch_size) == 0:
            self.num_micro_batch = global_batch_size // dp_size // micro_batch_size
        else:
            raise ValueError(
                "Global batch size must be divisible by DP size and micro batch size. "
                f"Got {global_batch_size} % ({dp_size} * {micro_batch_size}) != 0."
            )

        if not self.drop_last:
            raise ValueError("Drop last must be True.")

        self._batch_info: BatchInfo = {
            "micro_batch_size": self.micro_batch_size,
            "num_micro_batch": self.num_micro_batch,
            "cutoff_len": self.cutoff_len,
        }

        self._init_data_provider()

        self._is_resuming: bool = False
        self._data_iter = iter(self._data_provider)
        self._buffer = StatefulBuffer()

        logger.info_rank0(
            f"Init unified data loader with global batch size {self.global_batch_size}, "
            f"micro batch size {self.micro_batch_size}, "
            f"num micro batch {self.num_micro_batch}, "
            f"cutoff len {self.cutoff_len}, "

View on GitHub (pinned to f28afaf635)

Solutions

  1. Pass drop_last=True (the only supported mode in v1)
  2. If losing tail samples matters, oversize/repeat the dataset or accept the drop — v1's stateful resume requires uniform batches
  3. Stay on the v0 pipeline if you need partial final batches

Example fix

# before
sched = Batching(global_batch_size=128, micro_batch_size=32, drop_last=False)

# after
sched = Batching(global_batch_size=128, micro_batch_size=32, drop_last=True)
Defensive patterns

Strategy: validation

Validate before calling

assert drop_last is True, "v1 batching requires drop_last=True"

Prevention

When it happens

Trigger: Instantiating the v1 batching/scheduler class with drop_last=False. There is no code path that tolerates it — the check is immediate.

Common situations: Reusing a v0 DataLoader habit (v0 commonly runs drop_last=False) in v1 configs; wrapping the scheduler with a generic loader factory that defaults drop_last=False.

Related errors


AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14). Data as JSON: /api/errors/ccb57e1148152960. Report an issue: GitHub.