{"record":{"id":"996f89cab72d45d5","repo":"Lightning-AI/pytorch-lightning","slug":"configure-optimizers-must-include-a-monitor-when","errorCode":null,"errorMessage":"`configure_optimizers` must include a monitor when a `ReduceLROnPlateau` scheduler is used. For example: {\"optimizer\": optimizer, \"lr_scheduler\": scheduler, \"monitor\": \"metric_to_track\"}","messagePattern":"`configure_optimizers` must include a monitor when a `ReduceLROnPlateau` scheduler is used\\. For example: (.+?)","errorType":"exception","errorClass":"MisconfigurationException","httpStatus":null,"severity":"critical","filePath":"src/lightning/pytorch/core/optimizer.py","lineNumber":293,"sourceCode":"                \"reduce_on_plateau\", isinstance(scheduler[\"scheduler\"], optim.lr_scheduler.ReduceLROnPlateau)\n            )\n            if scheduler[\"reduce_on_plateau\"] and scheduler.get(\"monitor\") is None:\n                raise MisconfigurationException(\n                    \"The lr scheduler dict must include a monitor when a `ReduceLROnPlateau` scheduler is used.\"\n                    ' For example: {\"optimizer\": optimizer, \"lr_scheduler\":'\n                    ' {\"scheduler\": scheduler, \"monitor\": \"your_loss\"}}'\n                )\n            is_one_cycle = isinstance(scheduler[\"scheduler\"], optim.lr_scheduler.OneCycleLR)\n            if is_one_cycle and scheduler.get(\"interval\", \"epoch\") == \"epoch\":\n                rank_zero_warn(\n                    \"A `OneCycleLR` scheduler is using 'interval': 'epoch'.\"\n                    \" Are you sure you didn't mean 'interval': 'step'?\",\n                    category=RuntimeWarning,\n                )\n            config = LRSchedulerConfig(**scheduler)\n        elif isinstance(scheduler, ReduceLROnPlateau):\n            if monitor is None:\n                raise MisconfigurationException(\n                    \"`configure_optimizers` must include a monitor when a `ReduceLROnPlateau`\"\n                    \" scheduler is used. For example:\"\n                    ' {\"optimizer\": optimizer, \"lr_scheduler\": scheduler, \"monitor\": \"metric_to_track\"}'\n                )\n            config = LRSchedulerConfig(scheduler, reduce_on_plateau=True, monitor=monitor)\n        else:\n            config = LRSchedulerConfig(scheduler)\n        lr_scheduler_configs.append(config)\n    return lr_scheduler_configs\n\n\ndef _configure_schedulers_manual_opt(schedulers: list) -> list[LRSchedulerConfig]:\n    \"\"\"Convert each scheduler into `LRSchedulerConfig` structure with relevant information, when using manual\n    optimization.\"\"\"\n    lr_scheduler_configs = []\n    for scheduler in schedulers:\n        if isinstance(scheduler, dict):\n            # interval is not in this list even though the user needs to manually call the scheduler because","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/core/optimizer.py#L275-L311","documentation":"ReduceLROnPlateau needs a monitored metric to decide when to reduce the LR. If a ReduceLROnPlateau scheduler is configured without a 'monitor' key, Lightning raises MisconfigurationException with an example of the expected dict.","triggerScenarios":"Returning {'optimizer': opt, 'lr_scheduler': ReduceLROnPlateau(opt)} with no 'monitor' key.","commonSituations":"Copy-pasting a StepLR config and swapping in ReduceLROnPlateau without adding a monitor; not logging the metric referenced by monitor.","solutions":["Add 'monitor': '<logged_metric_name>' to the scheduler dict","Ensure the metric is actually logged via self.log(monitor, ...) or self.log_dict in validation/training"],"exampleFix":"# before\nreturn {'optimizer': opt, 'lr_scheduler': torch.optim.lr_scheduler.ReduceLROnPlateau(opt)}\n# after\nreturn {\n    'optimizer': opt,\n    'lr_scheduler': torch.optim.lr_scheduler.ReduceLROnPlateau(opt),\n    'monitor': 'val_loss',\n}\n# and in validation_step: self.log('val_loss', loss)","handlingStrategy":"validation","validationCode":"from torch.optim.lr_scheduler import ReduceLROnPlateau\nif isinstance(scheduler, ReduceLROnPlateau):\n    assert monitor, \"ReduceLROnPlateau requires a monitor\"","typeGuard":"def needs_monitor(sched) -> bool:\n    from torch.optim.lr_scheduler import ReduceLROnPlateau\n    return isinstance(sched, ReduceLROnPlateau)","tryCatchPattern":null,"preventionTips":["Always pair ReduceLROnPlateau with a logged validation metric","Test that the monitored name appears in trainer callback_metrics"],"tags":["lr-scheduler","reduce-lr-on-plateau","monitor","lightning"],"backgroundTag":"missing-required-argument","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}