Lightning-AI/pytorch-lightning · error · ValueError

Invalid mode. Has to be min or max, found {self.mode}

Error message

Invalid mode. Has to be min or max, found {self.mode}

What it means

`SpikeDetection._is_better` compares the current metric against the running mean using directionality given by `mode`, which must be "min" or "max". If mode is anything else (typo, wrong case, None), it raises ValueError listing the offending mode.

Source

Thrown at src/lightning/fabric/utilities/spike.py:140

            with open(self.exclude_batches_path, "w") as f:
                json.dump(self.bad_batches, f, indent=4)

        raise TrainingSpikeException(batch_idx=batch_idx)

    def _check_atol(self, val_a: Union[float, torch.Tensor], val_b: Union[float, torch.Tensor]) -> bool:
        return (self.atol is None) or bool(abs(val_a - val_b) >= abs(self.atol))  # type: ignore

    def _check_rtol(self, val_a: Union[float, torch.Tensor], val_b: Union[float, torch.Tensor]) -> bool:
        return (self.rtol is None) or bool(abs(val_a - val_b) >= abs(self.rtol * val_b))  # type: ignore

    def _is_better(self, diff_val: torch.Tensor) -> bool:
        if self.mode == "min":
            return bool((diff_val <= 0.0).all())
        if self.mode == "max":
            return bool((diff_val >= 0).all())

        raise ValueError(f"Invalid mode. Has to be min or max, found {self.mode}")

    def _update_stats(self, val: torch.Tensor) -> None:
        # only update if finite
        self.running_mean.update(val)
        self.last_val = val

    def state_dict(self) -> dict[str, Any]:
        return {
            "last_val": self.last_val.item() if isinstance(self.last_val, torch.Tensor) else self.last_val,
            "mode": self.mode,
            "warmup": self.warmup,
            "atol": self.atol,
            "rtol": self.rtol,
            "bad_batches": self.bad_batches,
            "bad_batches_path": self.exclude_batches_path,
            "running": self.running_mean.state_dict(),
            "mean": self.running_mean.base_metric.state_dict(),
        }

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set mode to exactly "min" or "max" (lowercase)
  2. If using "minimize"/"maximize" style configs, map them: `{"minimize": "min", "maximize": "max"}[cfg.mode]`
  3. Add a config assertion at startup so invalid modes fail fast

Example fix

# before
SpikeDetection(mode="minimize")  # or "MAX"

# after
SpikeDetection(mode="min")  # loss; use "max" for accuracy-style metrics
Defensive patterns

Strategy: validation

Validate before calling

mode = {"minimize": "min", "maximize": "max"}.get(mode, mode)
assert mode in ("min", "max"), f"bad mode: {mode}"

Prevention

When it happens

Trigger: Constructing `SpikeDetection(mode="minimum")`, `mode="MAX"`, `mode=None`, or mutating `self.mode` after init; any value other than exactly "min"/"max" hits the raise when a spike check is evaluated.

Common situations: Config files using verbose values like "minimize"/"maximize" (common with other libraries' `mode` conventions), YAML casing issues, copying configs from early-stopping setups that accept different strings.

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/fbf535876a79998e. Report an issue: GitHub.