Lightning-AI/pytorch-lightning · error · MisconfigurationException

to use {fn_name}, please disable automatic optimization: set

Error message

to use {fn_name}, please disable automatic optimization: set model property `automatic_optimization` as False

What it means

_verify_is_manual_optimization guards manual-optimization-only APIs (notably self.manual_backward). If the module still has automatic_optimization=True, the Trainer owns backward/optimizer steps, so calling manual_backward is contradictory and raises MisconfigurationException.

Source

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

        """Unfreeze all parameters for training.

        .. code-block:: python

            model = MyLightningModule(...)
            model.unfreeze()

        Returns:
            :class:`LightningModule` self with all parameters unfrozen.

        """
        for param in self.parameters():
            param.requires_grad = True

        return self.train()

    def _verify_is_manual_optimization(self, fn_name: str) -> None:
        if self.automatic_optimization:
            raise MisconfigurationException(
                f"to use {fn_name}, please disable automatic optimization:"
                " set model property `automatic_optimization` as False"
            )

    @torch.no_grad()
    def to_onnx(
        self,
        file_path: Union[str, Path, BytesIO, None] = None,
        input_sample: Optional[Any] = None,
        **kwargs: Any,
    ) -> Optional["ONNXProgram"]:
        """Saves the model in ONNX format.

        Args:
            file_path: The path of the file the onnx model should be saved to. Default: None (no file saved).
            input_sample: An input for tracing. Default: None (Use self.example_input_array)

            **kwargs: Will be passed to torch.onnx.export function.

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set self.automatic_optimization = False in __init__ before using manual_backward
  2. Then take over the loop: call self.manual_backward(loss), optimizer.step(), optimizer.zero_grad(), and self.optimizers handling yourself
  3. If you don't need manual control, remove manual_backward and just return loss from training_step

Example fix

# before
class M(L.LightningModule):
    def training_step(self, batch, idx):
        loss = self.step(batch)
        self.manual_backward(loss)  # raises
        return loss

# after
class M(L.LightningModule):
    def __init__(self):
        super().__init__()
        self.automatic_optimization = False
    def training_step(self, batch, idx):
        loss = self.step(batch)
        self.manual_backward(loss)
        self.optimizers().step()
        self.optimizers().zero_grad()
Defensive patterns

Strategy: validation

Validate before calling

if not self.automatic_optimization:
    self.manual_backward(loss)
else:
    return loss  # let the Trainer handle backward

Type guard

def is_manual_optimization(module) -> bool:
    return module.automatic_optimization is False

Try / catch

from lightning.pytorch.utilities.exceptions import MisconfigurationException
try:
    self.manual_backward(loss)
except MisconfigurationException:
    raise RuntimeError('set self.automatic_optimization = False in __init__')

Prevention

When it happens

Trigger: Calling self.manual_backward(loss) in training_step while self.automatic_optimization is True (the default).

Common situations: User added manual_backward for GANs/multiple optimizers or custom scaling without flipping the module flag; copied manual-optimization examples into an automatic-optimization module.

Related errors


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