Lightning-AI/pytorch-lightning · error · MisconfigurationException

No `{step_name}()` method defined to run `Trainer.{trainer_m

Error message

No `{step_name}()` method defined to run `Trainer.{trainer_method}`.

What it means

Raised by Lightning's configuration validator before starting validation or prediction: the LightningModule does not implement the required step method for the requested stage. `Trainer.validate()` needs `validation_step`, `Trainer.test()` needs `test_step`, and evaluation during `predict` requires `forward` or a step. The check runs when `trainer.fit`/`validate`/`test`/`predict` is called.

Source

Thrown at src/lightning/pytorch/trainer/configuration_validator.py:106

            " You can find migration examples in https://github.com/Lightning-AI/pytorch-lightning/pull/16520."
        )


def __verify_eval_loop_configuration(model: "pl.LightningModule", stage: str) -> None:
    step_name = "validation_step" if stage == "val" else f"{stage}_step"
    has_step = is_overridden(step_name, model)

    # predict_step is not required to be overridden
    if stage == "predict":
        if model.predict_step is None:
            raise MisconfigurationException("`predict_step` cannot be None to run `Trainer.predict`")
        if not has_step and not is_overridden("forward", model):
            raise MisconfigurationException("`Trainer.predict` requires `forward` method to run.")
    else:
        # verify minimum evaluation requirements
        if not has_step:
            trainer_method = "validate" if stage == "val" else stage
            raise MisconfigurationException(f"No `{step_name}()` method defined to run `Trainer.{trainer_method}`.")

        # check legacy hooks are not present
        epoch_end_name = "validation_epoch_end" if stage == "val" else "test_epoch_end"
        if callable(getattr(model, epoch_end_name, None)):
            raise NotImplementedError(
                f"Support for `{epoch_end_name}` has been removed in v2.0.0. `{type(model).__name__}` implements this"
                f" method. You can use the `on_{epoch_end_name}` hook instead. To access outputs, save them in-memory"
                " as instance attributes."
                " You can find migration examples in https://github.com/Lightning-AI/pytorch-lightning/pull/16520."
            )


def __verify_manual_optimization_support(trainer: "pl.Trainer", model: "pl.LightningModule") -> None:
    if model.automatic_optimization:
        return
    if trainer.gradient_clip_val is not None and trainer.gradient_clip_val > 0:
        raise MisconfigurationException(
            "Automatic gradient clipping is not supported for manual optimization."

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Implement the missing hook on your LightningModule: `validation_step` for `Trainer.validate`, `test_step` for `Trainer.test`, `predict_step` (or `forward`) for `Trainer.predict`.
  2. If you only meant to run inference, use `trainer.predict` with `forward` defined instead of `validate`.
  3. Verify the model instance you passed is the one with the hooks defined (not the base class or a fresh skeleton).

Example fix

# before
class Model(L.LightningModule):
    def training_step(self, batch, batch_idx): ...
trainer.validate(model)
# after
class Model(L.LightningModule):
    def training_step(self, batch, batch_idx): ...
    def validation_step(self, batch, batch_idx):
        x, y = batch
        return self.loss(self(x), y)
trainer.validate(model)
Defensive patterns

Strategy: validation

Validate before calling

from lightning.pytorch.core.mixins import HyperparametersMixin  # noqa
import inspect

def has_eval_step(model, stage):
    # stage: 'val' | 'test' | 'predict'
    required = {'val': 'validation_step', 'test': 'test_step'}.get(stage)
    if required:
        return callable(getattr(model, required, None)) and \
            type(model).__name__ != 'LightningModule'
    return callable(getattr(model, 'predict_step', None)) or \
        ('forward' in type(model).__dict__ or any('forward' in k.__dict__ for k in type(model).__mro__[1:-1]))

Type guard

def supports_stage(model: "pl.LightningModule", stage: str) -> bool:
    if stage in ('val', 'test'):
        return is_overridden(f'{stage}_step', model)
    return is_overridden('predict_step', model) or is_overridden('forward', model)

Try / catch

try:
    trainer.validate(model)
except MisconfigurationException as e:
    if 'method defined to run' in str(e):
        raise NotImplementedError(f'Model missing eval hook: {e}') from e
    raise

Prevention

When it happens

Trigger: Calling `trainer.validate(model)` without `def validation_step` overridden, `trainer.test(model)` without `test_step`, or `trainer.predict()` with neither a stage step nor `forward` overridden on the LightningModule.

Common situations: Copy-pasting a training-only model and calling validate/test; renaming hooks after migrating to Lightning 2.0; subclassing a base module that doesn't define the eval step; calling predict on a model whose forward is consumed by a decorator or renamed.

Related errors


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