Lightning-AI/pytorch-lightning · error · ValueError

An optimizer should be passed only once to the `setup` metho

Error message

An optimizer should be passed only once to the `setup` method.

What it means

Same double-setup guard as for models, but for optimizers: if any optimizer passed to fabric.setup()/setup_optimizers() is already a _FabricOptimizer, Fabric raises ValueError because re-wrapping would break the strategy's optimizer state.

Source

Thrown at src/lightning/fabric/fabric.py:1206

                " or change your code to directly call `fabric = Fabric(...); fabric.setup(...)` etc."
            )
        # wrap the run method, so we can inject setup logic or spawn processes for the user
        setattr(self, "run", partial(self._wrap_and_launch, self.run))

    def _validate_launched(self) -> None:
        if not self._launched and not isinstance(self._strategy, (SingleDeviceStrategy, DataParallelStrategy)):
            raise RuntimeError(
                "To use Fabric with more than one device, you must call `.launch()` or use the CLI:"
                " `fabric run --help`."
            )

    def _validate_setup(self, module: nn.Module, optimizers: Sequence[Optimizer]) -> None:
        self._validate_launched()
        if isinstance(module, _FabricModule):
            raise ValueError("A model should be passed only once to the `setup` method.")

        if any(isinstance(opt, _FabricOptimizer) for opt in optimizers):
            raise ValueError("An optimizer should be passed only once to the `setup` method.")

        if isinstance(self._strategy, FSDPStrategy) and any(
            _has_meta_device_parameters_or_buffers(optimizer) for optimizer in optimizers
        ):
            raise RuntimeError(
                "The optimizer has references to the model's meta-device parameters. Materializing them is"
                " is currently not supported unless you to set up the model and optimizer(s) separately."
                " Create and set up the model first through `model = fabric.setup_module(model)`. Then create the"
                " optimizer and set it up: `optimizer = fabric.setup_optimizers(optimizer)`."
            )

    def _validate_setup_module(self, module: nn.Module) -> None:
        self._validate_launched()
        if isinstance(module, _FabricModule):
            raise ValueError("A model should be passed only once to the `setup_module` method.")

    def _validate_setup_optimizers(self, optimizers: Sequence[Optimizer]) -> None:
        self._validate_launched()

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set up each optimizer exactly once; keep the returned reference
  2. If the model is already wrapped, only pass the new optimizer: fabric.setup_optimizers(new_opt)

Example fix

# before
opt = fabric.setup_optimizers(opt)
...
opt = fabric.setup_optimizers(opt)  # second time
# after
opt = fabric.setup_optimizers(opt)  # only once; reuse opt thereafter
Defensive patterns

Strategy: type-guard

Validate before calling

from lightning.fabric.wrappers import _FabricOptimizer
assert not any(isinstance(o, _FabricOptimizer) for o in optimizers)

Type guard

from lightning.fabric.wrappers import _FabricOptimizer
def needs_opt_setup(optimizers):
    return not any(isinstance(o, _FabricOptimizer) for o in optimizers)

Prevention

When it happens

Trigger: optimizer = fabric.setup_optimizers(optimizer) called twice, or calling fabric.setup(model, optimizer) after the optimizer was already set up in a previous call.

Common situations: Splitting model and optimizer setup across epochs or restarts; a training loop that re-enters an init function containing setup calls.

Related errors


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