Lightning-AI/pytorch-lightning · warning

You have overridden ` ` in both `LightningModule` and…

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.

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.

Appendix: 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)