Lightning-AI/pytorch-lightning · error · MisconfigurationException

`mode` can be {', '.join(mode_dict.keys())} but got {mode}

Error message

`mode` can be {', '.join(mode_dict.keys())} but got {mode}

What it means

ModelCheckpoint's mode decides whether 'best' means lowest ('min') or highest ('max') value of the monitored quantity. __init_monitor_mode accepts only the strings 'min' or 'max'; anything else raises MisconfigurationException before training starts.

Source

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

                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:
            raise MisconfigurationException(f"`mode` can be {', '.join(mode_dict.keys())} but got {mode}")

        self.kth_value, self.mode = mode_dict[mode]

    def __init_triggers(
        self,
        every_n_train_steps: Optional[int],
        every_n_epochs: Optional[int],
        train_time_interval: Optional[timedelta],
    ) -> None:
        # Default to running once after each validation epoch if neither
        # every_n_train_steps nor every_n_epochs is set
        if every_n_train_steps is None and every_n_epochs is None and train_time_interval is None:
            every_n_epochs = 1
            every_n_train_steps = 0
            log.debug("Both every_n_train_steps and every_n_epochs are not set. Setting every_n_epochs=1")
        else:
            every_n_epochs = every_n_epochs or 0
            every_n_train_steps = every_n_train_steps or 0

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Use exactly mode='min' (loss, error) or mode='max' (accuracy, F1)
  2. If the value comes from config, normalize it: mode=str(mode).lower() and validate against ('min','max')
  3. Add a startup assert for config-sourced mode strings

Example fix

# before
ModelCheckpoint(monitor='val_acc', mode='maximize')
# after
ModelCheckpoint(monitor='val_acc', mode='max')
Defensive patterns

Strategy: validation

Validate before calling

mode = str(cfg['mode']).lower()
assert mode in ('min', 'max'), f"mode must be 'min' or 'max', got {mode!r}"

Type guard

def is_valid_mode(m: str) -> bool:
    return isinstance(m, str) and m.lower() in ('min', 'max')

Prevention

When it happens

Trigger: Passing mode='minimum', mode='maximize', mode='Max', mode='asc'/'desc', or a typo like 'minn' to ModelCheckpoint; building the string dynamically from a config with unexpected casing.

Common situations: Configs written for other frameworks (e.g., mlflow or sklearn use different terminology); case sensitivity surprises ('Min' fails); typos in YAML files.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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