{"record":{"id":"e603e6e4906ace67","repo":"Lightning-AI/pytorch-lightning","slug":"the-provided-lr-scheduler-scheduler-class","errorCode":null,"errorMessage":"The provided lr scheduler `{scheduler.__class__.__name__}` is invalid. It should have `state_dict` and `load_state_dict` methods defined.","messagePattern":"The provided lr scheduler `(.+?)` is invalid\\. It should have `state_dict` and `load_state_dict` methods defined\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/core/optimizer.py","lineNumber":334,"sourceCode":"            if keys_to_warn:\n                rank_zero_warn(\n                    f\"The lr scheduler dict contains the key(s) {keys_to_warn}, but the keys will be ignored.\"\n                    \" You need to call `lr_scheduler.step()` manually in manual optimization.\",\n                    category=RuntimeWarning,\n                )\n\n            config = LRSchedulerConfig(**{key: scheduler[key] for key in scheduler if key not in invalid_keys})\n        else:\n            config = LRSchedulerConfig(scheduler)\n        lr_scheduler_configs.append(config)\n    return lr_scheduler_configs\n\n\ndef _validate_scheduler_api(lr_scheduler_configs: list[LRSchedulerConfig], model: \"pl.LightningModule\") -> None:\n    for config in lr_scheduler_configs:\n        scheduler = config.scheduler\n        if not isinstance(scheduler, _Stateful):\n            raise TypeError(\n                f\"The provided lr scheduler `{scheduler.__class__.__name__}` is invalid.\"\n                \" It should have `state_dict` and `load_state_dict` methods defined.\"\n            )\n\n        if (\n            not isinstance(scheduler, LRSchedulerTypeTuple)\n            and not is_overridden(\"lr_scheduler_step\", model)\n            and model.automatic_optimization\n        ):\n            raise MisconfigurationException(\n                f\"The provided lr scheduler `{scheduler.__class__.__name__}` doesn't follow PyTorch's LRScheduler\"\n                \" API. You should override the `LightningModule.lr_scheduler_step` hook with your own logic if\"\n                \" you are using a custom LR scheduler.\"\n            )\n\n\ndef _validate_multiple_optimizers_support(optimizers: list[Optimizer], model: \"pl.LightningModule\") -> None:\n    if is_param_in_hook_signature(model.training_step, \"optimizer_idx\", explicit=True):","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/core/optimizer.py#L316-L352","documentation":"Every scheduler Lightning manages must be checkpointable, i.e. implement state_dict/load_state_dict (the _Stateful protocol). A scheduler object lacking these methods raises TypeError during optimizer/scheduler setup.","triggerScenarios":"Returning a custom scheduler class that does not subclass torch.optim.lr_scheduler.LRScheduler and does not implement state_dict/load_state_dict.","commonSituations":"Hand-rolled warmup or custom LR wrappers that forget serialization methods needed for checkpoint resume.","solutions":["Subclass torch.optim.lr_scheduler.LRScheduler (which provides both methods)","Or implement state_dict() and load_state_dict(state_dict) on the custom scheduler class"],"exampleFix":"# before\nclass MySched:\n    def __init__(self, opt): self.opt = opt\n    def step(self): ...\n# after\nclass MySched(torch.optim.lr_scheduler.LRScheduler):\n    def get_lr(self):\n        return [g['lr'] for g in self.optimizer.param_groups]","handlingStrategy":"type-guard","validationCode":"assert hasattr(scheduler, \"state_dict\") and hasattr(scheduler, \"load_state_dict\")","typeGuard":"def is_stateful(sched) -> bool:\n    return hasattr(sched, \"state_dict\") and hasattr(sched, \"load_state_dict\")","tryCatchPattern":null,"preventionTips":["Subclass torch LRScheduler for custom schedules","Add a resume-from-checkpoint test to catch serialization gaps"],"tags":["lr-scheduler","checkpointing","type-error","lightning"],"backgroundTag":"missing-interface-method","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}