{"record":{"id":"3e07b224a6cc5373","repo":"Lightning-AI/pytorch-lightning","slug":"fn-ckpt-path-best-is-set-but-modelcheckpo-3e07b2","errorCode":null,"errorMessage":"`.{fn}(ckpt_path=\"best\")` is set but `ModelCheckpoint` is not configured to save the best model.","messagePattern":"`\\.(.+?)\\(ckpt_path=\"best\"\\)` is set but `ModelCheckpoint` is not configured to save the best model\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/trainer/connectors/checkpoint_connector.py","lineNumber":175,"sourceCode":"\n        if ckpt_path == \"best\":\n            if len(self.trainer.checkpoint_callbacks) > 1:\n                rank_zero_warn(\n                    f'`.{fn}(ckpt_path=\"best\")` is called with Trainer configured with multiple `ModelCheckpoint`'\n                    \" callbacks. It will use the best checkpoint path from first checkpoint callback.\"\n                )\n\n            if not self.trainer.checkpoint_callback:\n                raise ValueError(f'`.{fn}(ckpt_path=\"best\")` is set but `ModelCheckpoint` is not configured.')\n\n            has_best_model_path = self.trainer.checkpoint_callback.best_model_path\n            if hasattr(self.trainer.checkpoint_callback, \"best_model_path\") and not has_best_model_path:\n                if self.trainer.fast_dev_run:\n                    raise ValueError(\n                        f'You cannot execute `.{fn}(ckpt_path=\"best\")` with `fast_dev_run=True`.'\n                        f\" Please pass an exact checkpoint path to `.{fn}(ckpt_path=...)`\"\n                    )\n                raise ValueError(\n                    f'`.{fn}(ckpt_path=\"best\")` is set but `ModelCheckpoint` is not configured to save the best model.'\n                )\n            # load best weights\n            ckpt_path = getattr(self.trainer.checkpoint_callback, \"best_model_path\", None)\n\n        elif ckpt_path == \"last\":\n            candidates = {getattr(ft, \"ckpt_path\", None) for ft in ft_checkpoints}\n            for callback in self.trainer.checkpoint_callbacks:\n                if isinstance(callback, ModelCheckpoint):\n                    candidates |= callback._find_last_checkpoints(self.trainer)\n            candidates_fs = {path: get_filesystem(path) for path in candidates if path}\n            candidates_ts = {path: fs.modified(path) for path, fs in candidates_fs.items() if fs.exists(path)}\n            if not candidates_ts:\n                # not an error so it can be set and forget before the first `fit` run\n                rank_zero_warn(\n                    f'.{fn}(ckpt_path=\"last\") is set, but there is no last checkpoint available.'\n                    \" No checkpoint will be loaded. HINT: Set `ModelCheckpoint(..., save_last=True)`.\"\n                )","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/trainer/connectors/checkpoint_connector.py#L157-L193","documentation":"Raised when ckpt_path=\"best\" is requested, a ModelCheckpoint exists, but its best_model_path is empty because it was never configured to track a best model (no monitor) and nothing was saved. Resolving \"best\" is impossible without a monitored metric.","triggerScenarios":"Trainer(callbacks=[ModelCheckpoint()]) with default settings (no monitor) or save_top_k=0, followed by trainer.test(ckpt_path=\"best\"); also when fit did not run validation so the monitored metric never fired.","commonSituations":"Evaluating after training with a bare ModelCheckpoint; forgetting to set monitor when the model logs multiple metrics; calling .test(ckpt_path=\"best\") before .fit() has completed an epoch with validation.","solutions":["Configure ModelCheckpoint with a monitor: ModelCheckpoint(monitor=\"val_loss\", mode=\"min\", save_top_k=1)","Pass the explicit checkpoint file path to ckpt_path","Ensure validation runs (provide val_dataloaders) so the monitored metric is logged"],"exampleFix":"# before\ntrainer = Trainer(callbacks=[ModelCheckpoint()])\ntrainer.fit(model)\ntrainer.test(ckpt_path=\"best\")\n# after\ntrainer = Trainer(callbacks=[ModelCheckpoint(monitor=\"val_loss\", mode=\"min\", save_top_k=1)])\ntrainer.fit(model)\ntrainer.test(ckpt_path=\"best\")","handlingStrategy":"validation","validationCode":"from lightning.pytorch.callbacks import ModelCheckpoint\nmc = ModelCheckpoint(monitor=\"val_loss\", mode=\"min\", save_top_k=1)\nassert mc.monitor is not None, \"set monitor so best_model_path is populated\"","typeGuard":null,"tryCatchPattern":"try:\n    trainer.test(ckpt_path=\"best\")\nexcept ValueError as e:\n    if \"save the best model\" in str(e):\n        trainer.test(ckpt_path=mc.last_model_path or explicit)\n    else:\n        raise","preventionTips":["Always set monitor/mode on ModelCheckpoint","Ensure self.log(metric) is called in validation_step for the monitored name","Verify best_model_path is non-empty after fit before eval"],"tags":["lightning","model-checkpoint","monitor","best-model","test"],"backgroundTag":"checkpoint-not-found","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}