{"record":{"id":"83288679c2ecfaae","repo":"Stability-AI/generative-models","slug":"unknown-optimizer-optimizer-idx","errorCode":null,"errorMessage":"Unknown optimizer {optimizer_idx}","messagePattern":"Unknown optimizer (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"sgm/models/autoencoder.py","lineNumber":279,"sourceCode":"            self.log(\n                \"loss\",\n                aeloss.mean().detach(),\n                prog_bar=True,\n                logger=False,\n                on_epoch=False,\n                on_step=True,\n            )\n            return aeloss\n        elif optimizer_idx == 1:\n            # discriminator\n            discloss, log_dict_disc = self.loss(x, xrec, **extra_info)\n            # -> discriminator always needs to return a tuple\n            self.log_dict(\n                log_dict_disc, prog_bar=False, logger=True, on_step=True, on_epoch=True\n            )\n            return discloss\n        else:\n            raise NotImplementedError(f\"Unknown optimizer {optimizer_idx}\")\n\n    def training_step(self, batch: dict, batch_idx: int):\n        opts = self.optimizers()\n        if not isinstance(opts, list):\n            # Non-adversarial case\n            opts = [opts]\n        optimizer_idx = batch_idx % len(opts)\n        if self.global_step < self.disc_start_iter:\n            optimizer_idx = 0\n        opt = opts[optimizer_idx]\n        opt.zero_grad()\n        with opt.toggle_model():\n            loss = self.inner_training_step(\n                batch, batch_idx, optimizer_idx=optimizer_idx\n            )\n            self.manual_backward(loss)\n        opt.step()\n","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/Stability-AI/generative-models/blob/e8cd657656fa5d61688191730d0e03242bf4ed44/sgm/models/autoencoder.py#L261-L297","documentation":"AutoencodingEngine's inner_training_step handles two optimizer indices: 0 for the generator/autoencoder and 1 for the discriminator. Any other optimizer_idx (Lightning's optimize loop index) reaches the else branch and raises this NotImplementedError. This normally indicates the Lightning configure_optimizers returned more optimizers than the training step supports.","triggerScenarios":"Training the autoencoder with a Lightning version or subclass whose training loop calls inner_training_step with an optimizer_idx other than 0/1, or overriding configure_optimizers to return 3+ optimizers.","commonSituations":"Migrating across PyTorch Lightning versions where automatic optimization invokes training_step per optimizer; custom autoencoder subclasses returning extra optimizers; mis-wired multiple-optimizer configs.","solutions":["Ensure configure_optimizers returns exactly two optimizers (autoencoder and discriminator) when using adversarial training.","Pin/check the PyTorch Lightning version for changes in multi-optimizer training_step invocation semantics.","If adding a third training objective, extend inner_training_step to handle the new optimizer_idx instead of only 0/1."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"opts = model.configure_optimizers()\nif isinstance(opts, tuple):\n    opts = opts[0]\nassert len(opts) == 2, \"AutoencodingEngine supports exactly 2 optimizers (gen + disc)\"","typeGuard":null,"tryCatchPattern":"try:\n    trainer.fit(model, datamodule=dm)\nexcept NotImplementedError as e:\n    if \"Unknown optimizer\" in str(e):\n        raise RuntimeError(\"configure_optimizers must return exactly 2 optimizers\") from e","preventionTips":["Keep configure_optimizers returning exactly autoencoder + discriminator optimizers.","Check PyTorch Lightning changelog when upgrading multi-optimizer training code."],"tags":["pytorch-lightning","training-loop","optimizer"],"backgroundTag":"invalid-optimizer-index","analyzedSha":"e8cd657656fa5d61688191730d0e03242bf4ed44","analyzedAt":"2026-08-29T11:23:43.234Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}