Lightning-AI/pytorch-lightning · error · ValueError

The dataloader {dataloader} needs to subclass `torch.utils.d

Error message

The dataloader {dataloader} needs to subclass `torch.utils.data.DataLoader`

What it means

Raised as a ValueError by _get_dataloader_init_args_and_kwargs when Lightning needs to re-instantiate a dataloader (typically to inject a distributed sampler) but the object passed to a *_dataloader hook is not an instance of torch.utils.data.DataLoader. Lightning's introspection only knows how to reconstruct standard DataLoaders from their init args.

Source

Thrown at src/lightning/pytorch/utilities/data.py:145

            " to avoid having duplicate data."
        )
    return True


def _update_dataloader(
    dataloader: DataLoader, sampler: Union[Sampler, Iterable], mode: Optional[RunningStage] = None
) -> DataLoader:
    dl_args, dl_kwargs = _get_dataloader_init_args_and_kwargs(dataloader, sampler, mode)
    return _reinstantiate_wrapped_cls(dataloader, *dl_args, **dl_kwargs)


def _get_dataloader_init_args_and_kwargs(
    dataloader: DataLoader,
    sampler: Union[Sampler, Iterable],
    mode: Optional[RunningStage] = None,
) -> tuple[tuple[Any], dict[str, Any]]:
    if not isinstance(dataloader, DataLoader):
        raise ValueError(f"The dataloader {dataloader} needs to subclass `torch.utils.data.DataLoader`")

    was_wrapped = hasattr(dataloader, "__pl_saved_args")
    if was_wrapped:
        dl_args = dataloader.__pl_saved_args
        dl_kwargs = dataloader.__pl_saved_kwargs
        arg_names = dataloader.__pl_saved_arg_names
        original_dataset = dataloader.__dataset  # we have this saved from _wrap_init
    else:
        # get the dataloader instance attributes
        attrs = {k: v for k, v in vars(dataloader).items() if not k.startswith("_")}
        # We cannot be 100% sure the class sets dataset argument. Let's set it to None to be safe
        # and hope we can get it from the instance attributes
        original_dataset = None
        # not part of `vars`
        attrs["multiprocessing_context"] = dataloader.multiprocessing_context
        arg_names = ()

    # get the dataloader instance `__init__` parameters

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Subclass torch.utils.data.DataLoader for your custom dataloader instead of building a standalone iterable class
  2. Or return a plain torch.utils.data.DataLoader built over an IterableDataset if you need custom iteration logic
  3. Or set Trainer(use_distributed_sampler=False) so Lightning never needs to rebuild the dataloader

Example fix

# before
class MyLoader:  # not a DataLoader
    def __init__(self, ds): self.ds = ds
    def __iter__(self): return iter(self.ds)

# after
from torch.utils.data import DataLoader
class MyLoader(DataLoader):
    pass
Defensive patterns

Strategy: type-guard

Validate before calling

from torch.utils.data import DataLoader
dl = model.train_dataloader()
assert isinstance(dl, DataLoader), f'expected DataLoader, got {type(dl).__name__}'

Type guard

from torch.utils.data import DataLoader
from typing import Any

def is_data_loader(obj: Any) -> bool:
    return isinstance(obj, DataLoader)

Prevention

When it happens

Trigger: Returning a custom iterable/iterator class (e.g. a custom DataLoader-like object or a plain generator wrapper) from train_dataloader/val_dataloader in a distributed run where _update_dataloader is called; also returning None-DataLoader objects when use_distributed_sampler logic triggers re-instantiation.

Common situations: Wrapping a DataLoader in a custom class that doesn't subclass DataLoader; using third-party iterable dataset wrappers; refactoring code from raw PyTorch where any iterable was acceptable.

Related errors


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