Lightning-AI/pytorch-lightning · error · MisconfigurationException

`max_steps` must be a non-negative integer or -1 (infinite s

Error message

`max_steps` must be a non-negative integer or -1 (infinite steps). You passed in {max_steps}.

What it means

Raised by _TrainingEpochLoop.__init__ when the max_steps argument is an int strictly less than -1. -1 means 'unlimited steps' (the default) and 0 is allowed, so anything below -1 is treated as an invalid hyperparameter.

Source

Thrown at src/lightning/pytorch/loops/training_epoch_loop.py:76

    The validation is carried out by yet another loop,
    :class:`~lightning.pytorch.loops._EvaluationLoop`.

    In the ``run()`` method, the training epoch loop could in theory simply call the
    ``LightningModule.training_step`` already and perform the optimization.
    However, Lightning has built-in support for automatic optimization with multiple optimizers.
    For this reason there are actually two more loops nested under
    :class:`~lightning.pytorch.loops._TrainingEpochLoop`.

    Args:
        min_steps: The minimum number of steps (batches) to process
        max_steps: The maximum number of steps (batches) to process

    """

    def __init__(self, trainer: "pl.Trainer", min_steps: Optional[int] = None, max_steps: int = -1) -> None:
        super().__init__(trainer)
        if max_steps < -1:
            raise MisconfigurationException(
                f"`max_steps` must be a non-negative integer or -1 (infinite steps). You passed in {max_steps}."
            )
        self.min_steps = min_steps
        self.max_steps = max_steps

        self.batch_progress = _BatchProgress()
        self.scheduler_progress = _SchedulerProgress()

        self.automatic_optimization = _AutomaticOptimization(trainer)
        self.manual_optimization = _ManualOptimization(trainer)

        self.val_loop = loops._EvaluationLoop(
            trainer, TrainerFn.FITTING, RunningStage.VALIDATING, verbose=False, inference_mode=False
        )

        self._results = _ResultCollection(training=True)
        self._warning_cache = WarningCache()
        self._batches_that_stepped: int = 0

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set max_steps to a non-negative int or -1 (infinite)
  2. Clamp computed values: `max_steps = max(max_steps, -1)`
  3. Log/inspect the computed max_steps before constructing the Trainer

Example fix

# before
trainer = pl.Trainer(max_steps=steps_left - 10)  # can be -2

# after
trainer = pl.Trainer(max_steps=max(steps_left - 10, -1))
Defensive patterns

Strategy: validation

Validate before calling

max_steps = max(cfg['max_steps'], -1) if isinstance(cfg['max_steps'], int) else -1
trainer = pl.Trainer(max_steps=max_steps)

Type guard

def valid_max_steps(v) -> bool:
    return isinstance(v, int) and v >= -1

Prevention

When it happens

Trigger: Setting `Trainer(max_steps=-2)`; deriving max_steps from arithmetic like `max_steps=remaining_steps - overhang` that goes below -1; config files with negative step budgets.

Common situations: Resume-from-checkpoint logic computing remaining steps incorrectly; CLI misparsing; copying max_epochs-style -1 sentinel conventions while also subtracting values.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/1362aea7b577f63c. Report an issue: GitHub.