Lightning-AI/pytorch-lightning · error · MisconfigurationException

ModelCheckpoint(save_top_k={self.save_top_k}, monitor=None)

Error message

ModelCheckpoint(save_top_k={self.save_top_k}, monitor=None) is not a valid configuration. No quantity for top_k to track.

What it means

save_top_k determines how many 'best' checkpoints to keep by ranking a monitored quantity. Without a monitor, there is no quantity to rank, so only save_top_k in (-1, 0, 1) is meaningful: -1 saves everything, 0 saves nothing, 1 keeps the latest. Any other value with monitor=None is rejected at __init__.

Source

Thrown at src/lightning/pytorch/callbacks/model_checkpoint.py:688

            raise MisconfigurationException(
                f"Invalid value for every_n_train_steps={self._every_n_train_steps}. Must be >= 0"
            )
        if self._every_n_epochs < 0:
            raise MisconfigurationException(f"Invalid value for every_n_epochs={self._every_n_epochs}. Must be >= 0")

        every_n_train_steps_triggered = self._every_n_train_steps >= 1
        every_n_epochs_triggered = self._every_n_epochs >= 1
        train_time_interval_triggered = self._train_time_interval is not None
        if every_n_train_steps_triggered + every_n_epochs_triggered + train_time_interval_triggered > 1:
            raise MisconfigurationException(
                f"Combination of parameters every_n_train_steps={self._every_n_train_steps}, "
                f"every_n_epochs={self._every_n_epochs} and train_time_interval={self._train_time_interval} "
                "should be mutually exclusive."
            )

        if self.monitor is None and self.save_top_k not in (-1, 0, 1):
            # -1: save all epochs, 0: nothing is saved, 1: save last epoch
            raise MisconfigurationException(
                f"ModelCheckpoint(save_top_k={self.save_top_k}, monitor=None) is not a valid"
                " configuration. No quantity for top_k to track."
            )

    def __init_ckpt_dir(self, dirpath: Optional[_PATH], filename: Optional[str]) -> None:
        self._fs = get_filesystem(dirpath if dirpath else "")

        if dirpath and _is_local_file_protocol(dirpath if dirpath else ""):
            dirpath = os.path.realpath(os.path.expanduser(dirpath))

        self.dirpath = dirpath
        self.filename = filename

    def __init_monitor_mode(self, mode: str) -> None:
        torch_inf = torch.tensor(torch.inf)
        mode_dict = {"min": (torch_inf, "min"), "max": (-torch_inf, "max")}

        if mode not in mode_dict:

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set monitor to a metric your model logs (e.g., monitor='val_loss', mode='min') so save_top_k>1 has something to rank
  2. Or use save_top_k=1 to keep only the latest checkpoint when no metric is tracked
  3. Ensure the monitored metric is actually logged via self.log in validation/test steps

Example fix

# before
ModelCheckpoint(save_top_k=3)
# after
ModelCheckpoint(monitor='val_loss', mode='min', save_top_k=3)
Defensive patterns

Strategy: validation

Validate before calling

if ckpt_cfg.get('save_top_k', 1) not in (-1, 0, 1):
    assert ckpt_cfg.get('monitor'), 'save_top_k > 1 requires a monitor metric'

Type guard

def ckpt_config_valid(c: dict) -> bool:
    return c.get('save_top_k', 1) in (-1, 0, 1) or bool(c.get('monitor'))

Prevention

When it happens

Trigger: ModelCheckpoint(save_top_k=3) (or any value besides -1/0/1) without setting monitor; passing save_top_k from a config while forgetting the monitor key; setting save_top_k before deciding what metric to track.

Common situations: Default configs that assume a monitor (e.g., 'val_loss') exists but the model doesn't log it or monitor wasn't specified; transferring a Keras-style 'keep best 3' mental model without naming a metric.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/2d2f39ab6fc4887c. Report an issue: GitHub.