Lightning-AI/pytorch-lightning · warning

You have overridden `{hook_name}` in both `LightningModule`

Error message

You have overridden `{hook_name}` in both `LightningModule` and `LightningDataModule`. It will use the implementation from `LightningDataModule` instance.

What it means

DataConnector.get_instance resolves which object provides a data hook. If both the LightningModule and the LightningDataModule override the same hook (e.g. train_dataloader), a warning is emitted and the DataModule's implementation wins.

Source

Thrown at src/lightning/pytorch/trainer/connectors/data_connector.py:371

    model: "pl.LightningModule"
    datamodule: Optional["pl.LightningDataModule"]
    _valid_hooks: tuple[str, ...] = field(
        default=("on_before_batch_transfer", "transfer_batch_to_device", "on_after_batch_transfer")
    )

    def get_instance(self, hook_name: str) -> Union["pl.LightningModule", "pl.LightningDataModule"]:
        if hook_name not in self._valid_hooks:
            raise ValueError(
                f"`{hook_name}` is not a shared hook within `LightningModule` and `LightningDataModule`."
                f" Valid hooks are {self._valid_hooks}."
            )

        if self.datamodule is None:
            return self.model

        if is_overridden(hook_name, self.datamodule):
            if is_overridden(hook_name, self.model):
                warning_cache.warn(
                    f"You have overridden `{hook_name}` in both `LightningModule` and `LightningDataModule`."
                    " It will use the implementation from `LightningDataModule` instance."
                )
            return self.datamodule

        if is_overridden(hook_name, self.model):
            warning_cache.warn(
                f"You have overridden `{hook_name}` in `LightningModule` but have passed in a"
                " `LightningDataModule`. It will use the implementation from `LightningModule` instance."
            )
        return self.model


def _check_dataloader_iterable(
    dataloader: object,
    source: _DataLoaderSource,
    trainer_fn: TrainerFn,
) -> None:

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Delete the duplicated hook from one of the two classes (usually the LightningModule)
  2. If intentional, silence by accepting DataModule precedence; document it
  3. Keep dataloader logic exclusively in the DataModule for shared data pipelines

Example fix

# before
class M(LightningModule):
    def train_dataloader(self): return make_loader()
trainer = Trainer(); trainer.fit(M(), datamodule=dm)  # dm also defines train_dataloader
# after
class M(LightningModule):
    pass  # dataloader only in dm
trainer.fit(M(), datamodule=dm)
Defensive patterns

Strategy: validation

Validate before calling

from lightning.pytorch.utilities.model_helpers import is_overridden
for h in ('train_dataloader','val_dataloader','test_dataloader'):
    if is_overridden(h, dm) and is_overridden(h, model):
        print(f'both override {h}; datamodule wins')

Prevention

When it happens

Trigger: Passing datamodule=dm to the Trainer while the LightningModule also defines train_dataloader/val_dataloader, with dm defining the same hook.

Common situations: Refactoring a single-file script into module+datamodule and forgetting to delete the old dataloader methods in the model.

Related errors


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