{"record":{"id":"b44542cd1511e14c","repo":"Lightning-AI/pytorch-lightning","slug":"the-closure-hasn-t-been-executed-hint-did-you-ca","errorCode":null,"errorMessage":"The closure hasn't been executed. HINT: did you call `optimizer_closure()` in your `optimizer_step` hook? It could also happen because the `optimizer.step(optimizer_closure)` call did not execute it internally.","messagePattern":"The closure hasn't been executed\\. HINT: did you call `optimizer_closure\\(\\)` in your `optimizer_step` hook\\? It could also happen because the `optimizer\\.step\\(optimizer_closure\\)` call did not execute it internally\\.","errorType":"exception","errorClass":"MisconfigurationException","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/loops/optimization/closure.py","lineNumber":53,"sourceCode":"\n    This class provides a simple abstraction making the instance of this class callable like a function while capturing\n    the closure result and caching it.\n\n    \"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self._result: Optional[T] = None\n\n    def consume_result(self) -> T:\n        \"\"\"The cached result from the last time the closure was called.\n\n        Once accessed, the internal reference gets reset and the consumer will have to hold on to the reference as long\n        as necessary.\n\n        \"\"\"\n        if self._result is None:\n            raise MisconfigurationException(\n                \"The closure hasn't been executed.\"\n                \" HINT: did you call `optimizer_closure()` in your `optimizer_step` hook? It could also happen because\"\n                \" the `optimizer.step(optimizer_closure)` call did not execute it internally.\"\n            )\n        result, self._result = self._result, None  # free memory\n        return result\n\n    @abstractmethod\n    def closure(self, *args: Any, **kwargs: Any) -> T:\n        \"\"\"Implements the behavior of the closure once it is getting called.\"\"\"\n        pass\n\n    def __call__(self, *args: Any, **kwargs: Any) -> Any:\n        self._result = self.closure(*args, **kwargs)\n        return self\n","sourceCodeStart":35,"sourceCodeEnd":69,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/loops/optimization/closure.py#L35-L69","documentation":"Raised by Closure.consume_result when the optimizer closure was never executed before its result was consumed. In automatic optimization Lightning wraps forward+backward in a closure passed to optimizer.step(); if a custom optimizer_step hook neither calls closure() itself nor passes it to optimizer.step(closure) so it runs internally, there is no result to read.","triggerScenarios":"Overriding `def optimizer_step(self, epoch, batch_idx, optimizer, optimizer_closure): optimizer.step()` without invoking optimizer_closure(); using an optimizer wrapper/plugin that drops the closure argument; certain LBFGS-style optimizers requiring special handling.","commonSituations":"Custom optimizer_step for gradient clipping (though clip_grad is preferred), LR-decay-per-step hacks, or integrating Apex/fairscale optimizers while forgetting the closure.","solutions":["Call the closure first in your hook: `optimizer_closure(); optimizer.step()`","Or pass it through: `optimizer.step(closure=optimizer_closure)`","Prefer `Trainer(gradient_clip_val=...)` / configure_optimizers instead of overriding optimizer_step"],"exampleFix":"# before\ndef optimizer_step(self, epoch, batch_idx, optimizer, optimizer_closure):\n    optimizer.step()  # closure never runs\n\n# after\ndef optimizer_step(self, epoch, batch_idx, optimizer, optimizer_closure):\n    optimizer_closure()\n    optimizer.step()","handlingStrategy":"validation","validationCode":"# lint your overrides: any optimizer_step must reference optimizer_closure\nimport inspect\nsrc = inspect.getsource(MyModel.optimizer_step)\nassert 'optimizer_closure' in src","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call optimizer_closure() (or optimizer.step(closure=...)) inside custom optimizer_step","Prefer built-in mechanisms (gradient_clip_val, configure_optimizers) over optimizer_step overrides"],"tags":["pytorch-lightning","optimizer-step","closure","automatic-optimization"],"backgroundTag":"optimizer-closure-not-executed","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}