{"record":{"id":"ebea82b17da6d912","repo":"Lightning-AI/pytorch-lightning","slug":"modelcheckpoint-monitor-self-monitor-r-could","errorCode":null,"errorMessage":"`ModelCheckpoint(monitor={self.monitor!r})` could not find the monitored key in the returned metrics: {list(monitor_candidates)}. HINT: Did you call `log({self.monitor!r}, value)` in the `LightningModule`?","messagePattern":"`ModelCheckpoint\\(monitor=(.+?)\\)` could not find the monitored key in the returned metrics: (.+?)\\. HINT: Did you call `log\\((.+?), value\\)` in the `LightningModule`\\?","errorType":"validation","errorClass":"MisconfigurationException","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/callbacks/model_checkpoint.py","lineNumber":587,"sourceCode":"                \" `best_k_models` won't be reloaded. Only `best_model_path` will be reloaded.\"\n            )\n\n        self.best_model_path = state_dict[\"best_model_path\"]\n\n    def _save_topk_checkpoint(self, trainer: \"pl.Trainer\", monitor_candidates: dict[str, Tensor]) -> None:\n        if self.save_top_k == 0:\n            return\n\n        # validate metric\n        if self.monitor is not None:\n            if self.monitor not in monitor_candidates:\n                m = (\n                    f\"`ModelCheckpoint(monitor={self.monitor!r})` could not find the monitored key in the returned\"\n                    f\" metrics: {list(monitor_candidates)}.\"\n                    f\" HINT: Did you call `log({self.monitor!r}, value)` in the `LightningModule`?\"\n                )\n                if trainer.fit_loop.epoch_loop.val_loop._has_run:\n                    raise MisconfigurationException(m)\n                warning_cache.warn(m)\n            self._save_monitor_checkpoint(trainer, monitor_candidates)\n        else:\n            self._save_none_monitor_checkpoint(trainer, monitor_candidates)\n\n    def _save_checkpoint(self, trainer: \"pl.Trainer\", filepath: str) -> None:\n        \"\"\"Save the checkpoint to the given filepath.\n\n        For manual optimization, we rely on the fact that the model's training_step method saves the model state before\n        the optimizer step, so we can use that state directly.\n\n        \"\"\"\n        trainer.save_checkpoint(filepath, self.save_weights_only)\n        self._last_global_step_saved = trainer.global_step\n        self._last_checkpoint_saved = filepath\n\n        # notify loggers\n        if trainer.is_global_zero:","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/callbacks/model_checkpoint.py#L569-L605","documentation":"When `save_top_k >= 1` and a monitor is set, ModelCheckpoint looks for the monitored key among the metrics it can see. If missing, and validation has already run at least once (`val_loop._has_run`), it raises MisconfigurationException with a hint to log the key; otherwise it only warns once.","triggerScenarios":"`ModelCheckpoint(monitor='val_f1')` but the module never calls `self.log('val_f1', ...)`; metric logged only in training while checkpointing expects a validation metric; monitor name typo; metric logged with `sync_dist` conditions so it's absent on some ranks.","commonSituations":"Renaming logged metrics and forgetting the checkpoint monitor; using a different logger prefix ('val/f1' vs 'val_f1'); logging inside `on_validation_epoch_end` with add_n_metrics misconfigured; logging on epoch vs step mismatch.","solutions":["Match names exactly: log `self.log('val_f1', ...)` in validation_step (with on_epoch=True or in validation_epoch_end) and set monitor='val_f1'","Check the list of available metric keys printed in the error and use one of them","If validation hasn't run yet, note it only warns the first time — ensure the metric exists before the first checkpointing event"],"exampleFix":"# before\n# monitor='val_f1' but module logs 'val_acc'\nModelCheckpoint(monitor='val_f1')\n# after\ndef validation_step(self, batch, batch_idx):\n    self.log('val_f1', f1, prog_bar=True)\nModelCheckpoint(monitor='val_f1')","handlingStrategy":"validation","validationCode":"# smoke check: run 1 val epoch and confirm the monitor key appears\n# assert monitor in trainer.callback_metrics after a sanity run\nmonitor = 'val_loss'\n# after trainer.validate / a 1-step fit:\n# assert monitor in trainer.callback_metrics","typeGuard":null,"tryCatchPattern":"try:\n    trainer.fit(model)\nexcept MisconfigurationException as e:\n    if 'could not find the monitored key' in str(e):\n        avail = eval(e.args[0].split('metrics: ')[1].split('.')[0])  # or parse manually\n        # choose a corrected monitor from avail and retry\n        raise","preventionTips":["Define metric names as module-level constants used by both self.log and ModelCheckpoint","Run a fast smoke fit (limit_train_batches=1, limit_val_batches=1) before long runs","Cross-check logged keys via logger output or trainer.callback_metrics"],"tags":["lightning","model-checkpoint","metric-not-found","monitor"],"backgroundTag":"missing-metric-key","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}