{"record":{"id":"8adb4ac87ee2bbf4","repo":"Lightning-AI/pytorch-lightning","slug":"support-for-epoch-end-name-has-been-removed-in","errorCode":null,"errorMessage":"Support for `{epoch_end_name}` has been removed in v2.0.0. `{type(model).__name__}` implements this method. You can use the `on_{epoch_end_name}` hook instead. To access outputs, save them in-memory as instance attributes. You can find migration examples in https://github.com/Lightning-AI/pytorch-lightning/pull/16520.","messagePattern":"Support for `(.+?)` has been removed in v2\\.0\\.0\\. `(.+?)` implements this method\\. You can use the `on_(.+?)` hook instead\\. To access outputs, save them in-memory as instance attributes\\. You can find migration examples in https://github\\.com/Lightning-AI/pytorch-lightning/pull/16520\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/trainer/configuration_validator.py","lineNumber":111,"sourceCode":"    step_name = \"validation_step\" if stage == \"val\" else f\"{stage}_step\"\n    has_step = is_overridden(step_name, model)\n\n    # predict_step is not required to be overridden\n    if stage == \"predict\":\n        if model.predict_step is None:\n            raise MisconfigurationException(\"`predict_step` cannot be None to run `Trainer.predict`\")\n        if not has_step and not is_overridden(\"forward\", model):\n            raise MisconfigurationException(\"`Trainer.predict` requires `forward` method to run.\")\n    else:\n        # verify minimum evaluation requirements\n        if not has_step:\n            trainer_method = \"validate\" if stage == \"val\" else stage\n            raise MisconfigurationException(f\"No `{step_name}()` method defined to run `Trainer.{trainer_method}`.\")\n\n        # check legacy hooks are not present\n        epoch_end_name = \"validation_epoch_end\" if stage == \"val\" else \"test_epoch_end\"\n        if callable(getattr(model, epoch_end_name, None)):\n            raise NotImplementedError(\n                f\"Support for `{epoch_end_name}` has been removed in v2.0.0. `{type(model).__name__}` implements this\"\n                f\" method. You can use the `on_{epoch_end_name}` hook instead. To access outputs, save them in-memory\"\n                \" as instance attributes.\"\n                \" You can find migration examples in https://github.com/Lightning-AI/pytorch-lightning/pull/16520.\"\n            )\n\n\ndef __verify_manual_optimization_support(trainer: \"pl.Trainer\", model: \"pl.LightningModule\") -> None:\n    if model.automatic_optimization:\n        return\n    if trainer.gradient_clip_val is not None and trainer.gradient_clip_val > 0:\n        raise MisconfigurationException(\n            \"Automatic gradient clipping is not supported for manual optimization.\"\n            f\" Remove `Trainer(gradient_clip_val={trainer.gradient_clip_val})`\"\n            \" or switch to automatic optimization.\"\n        )\n    if trainer.accumulate_grad_batches != 1:\n        raise MisconfigurationException(","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/trainer/configuration_validator.py#L93-L129","documentation":"Lightning 2.0 removed the `validation_epoch_end` / `test_epoch_end` hooks. If your module still defines them as callable methods, Lightning raises NotImplementedError at run start and points you to the `on_validation_epoch_end` / `on_test_epoch_end` hooks instead, with outputs stored as instance attributes.","triggerScenarios":"A LightningModule (including inherited base classes) defines `validation_epoch_end` or `test_epoch_end` and you call `trainer.fit/validate/test`. This includes code migrated from Lightning 1.x without updating the hooks.","commonSituations":"Upgrading a project from lightning <2.0 to >=2.0; old tutorials/examples; a shared corporate base model class still carrying the legacy hook.","solutions":["Delete `validation_epoch_end`/`test_epoch_end` and move aggregation logic into `on_validation_epoch_end`/`on_test_epoch_end`.","Collect step outputs manually: append them to a list in `validation_step` and compute metrics in the epoch-end hook.","If a dependency ships the legacy hook, upgrade that dependency or override the method with `pass` in your subclass.","See migration examples in PR #16520 linked in the message."],"exampleFix":"# before\nclass Model(L.LightningModule):\n    def validation_step(self, batch, idx):\n        return self(loss)\n    def validation_epoch_end(self, outputs):\n        self.log('val_loss', torch.stack(outputs).mean())\n# after\nclass Model(L.LightningModule):\n    def __init__(self):\n        super().__init__()\n        self.val_outputs = []\n    def validation_step(self, batch, idx):\n        loss = self.step(batch)\n        self.val_outputs.append(loss)\n        return loss\n    def on_validation_epoch_end(self):\n        self.log('val_loss', torch.stack(self.val_outputs).mean())\n        self.val_outputs.clear()","handlingStrategy":"validation","validationCode":"import inspect\n\ndef has_legacy_epoch_end(model):\n    return any(callable(getattr(model, n, None)) and getattr(model, n, None) is not getattr(object, n, None)\n               for n in ('validation_epoch_end', 'test_epoch_end'))\n\nif has_legacy_epoch_end(model):\n    raise RuntimeError('Migrate *_epoch_end hooks to on_*_epoch_end (Lightning 2.0)')","typeGuard":"def is_lightning2_compatible(model) -> bool:\n    return not any(callable(getattr(model, n, None)) for n in ('validation_epoch_end', 'test_epoch_end'))","tryCatchPattern":"try:\n    trainer.fit(model)\nexcept NotImplementedError as e:\n    if 'removed in v2.0.0' in str(e):\n        # strip legacy hooks and re-run\n        ...\n    raise","preventionTips":["Run the Lightning 2.0 migration guides / `lightning` upgrade checklist when bumping versions.","Add a unit test that instantiates the trainer config for each model to catch validation errors early.","Search the codebase for '_epoch_end(' during upgrades."],"tags":["pytorch-lightning","migration","v2-breaking-change","legacy-hooks"],"backgroundTag":"removed-api-migration-error","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}