{"record":{"id":"f8f146fc771454fe","repo":"Lightning-AI/pytorch-lightning","slug":"unknown-configuration-for-model-optimizers-output","errorCode":null,"errorMessage":"Unknown configuration for model optimizers. Output from `model.configure_optimizers()` should be one of:\n * `Optimizer`\n * [`Optimizer`]\n * ([`Optimizer`], [`LRScheduler`])\n * {\"optimizer\": `Optimizer`, (optional) \"lr_scheduler\": `LRScheduler`}\n","messagePattern":"Unknown configuration for model optimizers\\. Output from `model\\.configure_optimizers\\(\\)` should be one of:\n \\* `Optimizer`\n \\* \\[`Optimizer`\\]\n \\* \\(\\[`Optimizer`\\], \\[`LRScheduler`\\]\\)\n \\* (.+?)\n","errorType":"exception","errorClass":"MisconfigurationException","httpStatus":null,"severity":"critical","filePath":"src/lightning/pytorch/core/optimizer.py","lineNumber":239,"sourceCode":"        _validate_optim_conf(optim_conf)\n        optimizers = [optim_conf[\"optimizer\"]]\n        monitor = optim_conf.get(\"monitor\", None)\n        lr_schedulers = [optim_conf[\"lr_scheduler\"]] if \"lr_scheduler\" in optim_conf else []\n    # multiple dictionaries\n    elif isinstance(optim_conf, (list, tuple)) and all(isinstance(d, dict) for d in optim_conf):\n        for opt_dict in optim_conf:\n            _validate_optim_conf(opt_dict)\n        optimizers = [opt_dict[\"optimizer\"] for opt_dict in optim_conf]\n        scheduler_dict = lambda scheduler: dict(scheduler) if isinstance(scheduler, dict) else {\"scheduler\": scheduler}\n        lr_schedulers = [\n            scheduler_dict(opt_dict[\"lr_scheduler\"]) for opt_dict in optim_conf if \"lr_scheduler\" in opt_dict\n        ]\n    # single list or tuple, multiple optimizer\n    elif isinstance(optim_conf, (list, tuple)) and all(isinstance(opt, Optimizable) for opt in optim_conf):\n        optimizers = list(optim_conf)\n    # unknown configuration\n    else:\n        raise MisconfigurationException(\n            \"Unknown configuration for model optimizers.\"\n            \" Output from `model.configure_optimizers()` should be one of:\\n\"\n            \" * `Optimizer`\\n\"\n            \" * [`Optimizer`]\\n\"\n            \" * ([`Optimizer`], [`LRScheduler`])\\n\"\n            ' * {\"optimizer\": `Optimizer`, (optional) \"lr_scheduler\": `LRScheduler`}\\n'\n        )\n    return optimizers, lr_schedulers, monitor\n\n\ndef _configure_schedulers_automatic_opt(schedulers: list, monitor: Optional[str]) -> list[LRSchedulerConfig]:\n    \"\"\"Convert each scheduler into `LRSchedulerConfig` with relevant information, when using automatic optimization.\"\"\"\n    lr_scheduler_configs = []\n    for scheduler in schedulers:\n        if isinstance(scheduler, dict):\n            # check provided keys\n            supported_keys = {field.name for field in fields(LRSchedulerConfig)}\n            extra_keys = scheduler.keys() - supported_keys","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/core/optimizer.py#L221-L257","documentation":"Lightning parses the return value of LightningModule.configure_optimizers() and only accepts an Optimizer, a list of Optimizers, a (optimizers, schedulers) tuple, or dicts with 'optimizer'/'lr_scheduler' keys. Anything else (a dict with wrong keys, a scheduler alone, a number, etc.) raises MisconfigurationException listing the accepted shapes.","triggerScenarios":"Returning e.g. {'optimizer': opt, 'lr_sched': sched} (typo'd key), return scheduler without optimizer, or returning a raw tuple of mismatched types from configure_optimizers.","commonSituations":"First-time users returning a learning-rate scheduler alone, typos in dict keys, or returning [optimizer, scheduler] as a flat list (scheduler mistaken for an optimizer).","solutions":["Return one of the documented shapes, e.g. return (optimizers, schedulers) or {'optimizer': opt, 'lr_scheduler': sched}","Check for typos in keys ('lr_scheduler' not 'lr_sched', not 'scheduler' at top level)","If returning a list, ensure every element is an Optimizer — schedulers go in a separate list in a tuple"],"exampleFix":"# before\ndef configure_optimizers(self):\n    return [self.opt, self.sched]\n# after\ndef configure_optimizers(self):\n    opt = torch.optim.AdamW(self.parameters(), lr=1e-3)\n    sched = torch.optim.lr_scheduler.StepLR(opt, 1)\n    return [opt], [sched]","handlingStrategy":"validation","validationCode":"from lightning.pytorch.core.optimizer import _configure_optimizers  # or validate shape yourself\nfrom torch.optim import Optimizer\nconf = model.configure_optimizers()\nok = isinstance(conf, Optimizer) or (\n    isinstance(conf, (list, tuple)) and conf and all(isinstance(o, Optimizer) for o in conf)\n) or (isinstance(conf, dict) and \"optimizer\" in conf)\nassert ok, f\"bad configure_optimizers output: {type(conf)}\"","typeGuard":"def valid_optim_conf(conf) -> bool:\n    from torch.optim import Optimizer\n    if isinstance(conf, Optimizer):\n        return True\n    if isinstance(conf, dict):\n        return isinstance(conf.get(\"optimizer\"), Optimizer)\n    if isinstance(conf, (list, tuple)):\n        return all(isinstance(o, Optimizer) for o in conf)\n    return False","tryCatchPattern":"try:\n    trainer.fit(model)\nexcept MisconfigurationException as e:\n    if \"configure_optimizers\" in str(e):\n        fix_model_optimizers(model)  # inspect return shape\n    raise","preventionTips":["Return the canonical (optimizers, schedulers) tuple shape","Add a unit test asserting configure_optimizers returns an accepted shape"],"tags":["configure-optimizers","validation","lightning","misconfiguration"],"backgroundTag":"invalid-configuration-shape","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}