Lightning-AI/pytorch-lightning · error · MisconfigurationException

"`val_check_interval` should be an integer or a time-based d

Error message

"`val_check_interval` should be an integer or a time-based duration (str 'DD:HH:MM:SS', " "datetime.timedelta, or dict kwargs for timedelta) when `check_val_every_n_epoch=None`."

What it means

Raised when check_val_every_n_epoch=None but val_check_interval is a float. In that mode, fractional epoch-based validation is ambiguous, so only ints or time-based durations (str 'DD:HH:MM:SS', datetime.timedelta, dict of timedelta kwargs) are accepted.

Source

Thrown at src/lightning/pytorch/trainer/connectors/data_connector.py:66

    def __init__(self, trainer: "pl.Trainer"):
        self.trainer = trainer
        self._datahook_selector: Optional[_DataHookSelector] = None

    def on_trainer_init(
        self,
        val_check_interval: Optional[Union[int, float, str, timedelta, dict]],
        reload_dataloaders_every_n_epochs: int,
        check_val_every_n_epoch: Optional[int],
    ) -> None:
        self.trainer.datamodule = None

        if check_val_every_n_epoch is not None and not isinstance(check_val_every_n_epoch, int):
            raise MisconfigurationException(
                f"`check_val_every_n_epoch` should be an integer, found {check_val_every_n_epoch!r}."
            )

        if check_val_every_n_epoch is None and isinstance(val_check_interval, float):
            raise MisconfigurationException(
                "`val_check_interval` should be an integer or a time-based duration (str 'DD:HH:MM:SS', "
                "datetime.timedelta, or dict kwargs for timedelta) when `check_val_every_n_epoch=None`."
            )

        self.trainer.check_val_every_n_epoch = check_val_every_n_epoch

        if not isinstance(reload_dataloaders_every_n_epochs, int) or (reload_dataloaders_every_n_epochs < 0):
            raise MisconfigurationException(
                f"`reload_dataloaders_every_n_epochs` should be an int >= 0, got {reload_dataloaders_every_n_epochs}."
            )

        self.trainer.reload_dataloaders_every_n_epochs = reload_dataloaders_every_n_epochs

    def prepare_data(self) -> None:
        trainer = self.trainer

        # on multi-gpu jobs we only want to manipulate (download, etc) on node_rank=0, local_rank=0
        # or in the case where each node needs to do its own manipulation in which case just local_rank=0

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Use an int val_check_interval (steps within an epoch) when check_val_every_n_epoch=None
  2. Use a time-based duration: val_check_interval="00:30:00" or datetime.timedelta(minutes=30) or dict(hours=1, minutes=30)
  3. Set check_val_every_n_epoch to an int if you wanted float-style per-epoch frequency — instead express it via int interval or check_val_every_n_epoch=k

Example fix

# before
trainer = Trainer(val_check_interval=0.5, check_val_every_n_epoch=None)
# after
import datetime
trainer = Trainer(val_check_interval=100, check_val_every_n_epoch=None)  # every 100 steps
# or time-based
trainer = Trainer(val_check_interval=datetime.timedelta(minutes=30))
Defensive patterns

Strategy: type-guard

Validate before calling

import datetime
def normalize(v):
    if isinstance(v, float):
        v = int(v) if v.is_integer() else None
    assert not isinstance(v, float), "use int or time-based duration for val_check_interval"
    return v
val_check_interval = normalize(cfg["val_check_interval"])

Type guard

def is_valid_val_check_interval(v) -> bool:
    import datetime
    return isinstance(v, (int, datetime.timedelta)) or isinstance(v, str) or isinstance(v, dict)

Prevention

When it happens

Trigger: Trainer(check_val_every_n_epoch=None, val_check_interval=0.5) or val_check_interval=100.0 with the default check_val_every_n_epoch; classic case is val_check_interval=0.25 copied from older configs while explicitly setting check_val_every_n_epoch=None.

Common situations: Migrating configs between Lightning versions where float semantics changed; time-based validation setups mixing duration strings with float leftovers.

Related errors


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