Lightning-AI/pytorch-lightning · error · RuntimeError

{self.__class__.__qualname__} is not attached to a `Trainer`

Error message

{self.__class__.__qualname__} is not attached to a `Trainer`.

What it means

LightningModule.trainer raises RuntimeError when accessed before the Trainer has attached itself to the module (which happens inside trainer.fit/validate/test/predict). Any property/method that reads self.trainer outside Trainer-managed control flow will fail. A special case returns a shim when the module is attached to Fabric instead.

Source

Thrown at src/lightning/pytorch/core/module.py:218

        if not self.trainer.lr_scheduler_configs:
            return None

        # ignore other keys "interval", "frequency", etc.
        lr_schedulers: list[LRSchedulerPLType] = [config.scheduler for config in self.trainer.lr_scheduler_configs]

        # single scheduler
        if len(lr_schedulers) == 1:
            return lr_schedulers[0]

        # multiple schedulers
        return lr_schedulers

    @property
    def trainer(self) -> "pl.Trainer":
        if self._fabric is not None:
            return _TrainerFabricShim(fabric=self._fabric)  # type: ignore[return-value]
        if not self._jit_is_scripting and self._trainer is None:
            raise RuntimeError(f"{self.__class__.__qualname__} is not attached to a `Trainer`.")
        return self._trainer  # type: ignore[return-value]

    @trainer.setter
    def trainer(self, trainer: Optional["pl.Trainer"]) -> None:
        for v in self.children():
            if isinstance(v, LightningModule):
                v.trainer = trainer
        self._trainer = trainer

    @property
    def fabric(self) -> Optional["lf.Fabric"]:
        return self._fabric

    @fabric.setter
    def fabric(self, fabric: Optional["lf.Fabric"]) -> None:
        for v in self.children():
            if isinstance(v, LightningModule):
                v.fabric = fabric

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Move trainer-dependent logic into hooks that run under Trainer control (on_train_start, training_step, etc.)
  2. If testing, attach a Trainer first or mock the attribute
  3. Check `model._trainer is not None` (or use getattr guard) before accessing .trainer
  4. For Fabric workflows, attach the module via fabric.setup(model) so the shim is returned

Example fix

# before
class M(L.LightningModule):
    def __init__(self):
        super().__init__()
        print(self.trainer.max_epochs)  # RuntimeError

# after
class M(L.LightningModule):
    def on_train_start(self):
        print(self.trainer.max_epochs)  # Trainer attached here
Defensive patterns

Strategy: validation

Validate before calling

if model._trainer is None and model._fabric is None:
    raise RuntimeError('attach model to a Trainer (trainer.fit) before accessing model.trainer')

Type guard

def is_attached(module) -> bool:
    return module._trainer is not None or module._fabric is not None

Try / catch

try:
    t = model.trainer
except RuntimeError as e:
    if 'not attached' in str(e):
        t = None  # defer trainer-dependent logic to hooks
    else:
        raise

Prevention

When it happens

Trigger: Accessing self.trainer (directly or via self.log, self.device in some paths, checkpoint saving code) in __init__, in a plain script before trainer.fit, or in a datamodule hook not driven by the Trainer.

Common situations: Calling model.trainer in unit tests without a Trainer; using self.trainer.global_step in __init__; accessing trainer-dependent attributes when running the module standalone or with Fabric (where _fabric shim applies only if attached).

Related errors


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