Lightning-AI/pytorch-lightning · error · MisconfigurationException

m.format("on_epoch", on_epoch, fx_name, fx_config["allowed_o

Error message

m.format("on_epoch", on_epoch, fx_name, fx_config["allowed_on_epoch"])

What it means

Mirror of the on_step check: each hook restricts on_epoch too. When self.log(..., on_epoch=X) passes a value outside fx_config['allowed_on_epoch'] (e.g. on_epoch=True in training_step when only step logging is allowed for that configuration), check_logging_levels raises this MisconfigurationException.

Source

Thrown at src/lightning/pytorch/trainer/connectors/logger_connector/fx_validator.py:189

        fx_config = cls.functions[fx_name]
        assert fx_config is not None
        on_step = fx_config["default_on_step"] if on_step is None else on_step
        on_epoch = fx_config["default_on_epoch"] if on_epoch is None else on_epoch
        return on_step, on_epoch

    @classmethod
    def check_logging_levels(cls, fx_name: str, on_step: bool, on_epoch: bool) -> None:
        """Check if the logging levels are allowed in the given hook."""
        fx_config = cls.functions[fx_name]
        assert fx_config is not None
        m = "You can't `self.log({}={})` inside `{}`, must be one of {}."
        if on_step not in fx_config["allowed_on_step"]:
            msg = m.format("on_step", on_step, fx_name, fx_config["allowed_on_step"])
            raise MisconfigurationException(msg)

        if on_epoch not in fx_config["allowed_on_epoch"]:
            msg = m.format("on_epoch", on_epoch, fx_name, fx_config["allowed_on_epoch"])
            raise MisconfigurationException(msg)

    @classmethod
    def check_logging_and_get_default_levels(
        cls, fx_name: str, on_step: Optional[bool], on_epoch: Optional[bool]
    ) -> tuple[bool, bool]:
        """Check if the given hook name is allowed to log and return logging levels."""
        cls.check_logging(fx_name)
        on_step, on_epoch = cls.get_default_logging_levels(fx_name, on_step, on_epoch)
        cls.check_logging_levels(fx_name, on_step, on_epoch)
        return on_step, on_epoch

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set on_epoch to a value from the message's allowed set, e.g. self.log('x', x, on_step=True, on_epoch=False) in training_step
  2. Drop the explicit flag and let Lightning pick defaults for the hook
  3. Manually aggregate the metric yourself (accumulate in a list, log the mean at epoch end via a callback logger) if you truly need epoch-level values

Example fix

# before
self.log('batch_norm_ratio', r, on_step=True, on_epoch=True)  # on_epoch not allowed

# after
self.log('batch_norm_ratio', r, on_step=True, on_epoch=False)
Defensive patterns

Strategy: validation

Validate before calling

from lightning.pytorch.trainer.connectors.logger_connector.fx_validator import _FxValidator
cfg = _FxValidator.functions[hook_name]
assert on_epoch in cfg["allowed_on_epoch"], f"allowed: {cfg['allowed_on_epoch']}"

Type guard

def epoch_allowed(hook_name: str, on_epoch: bool) -> bool:
    from lightning.pytorch.trainer.connectors.logger_connector import fx_validator
    cfg = fx_validator._FxValidator.functions[hook_name]
    return cfg is not None and on_epoch in cfg["allowed_on_epoch"]

Prevention

When it happens

Trigger: self.log('x', x, on_epoch=True) in a hook whose allowed_on_epoch is False; e.g. certain training_step configurations or custom hooks where epoch aggregation is not supported; any on_epoch value outside the allowed set printed in the message.

Common situations: Forcing epoch aggregation for speed-critical training metrics; mixing prog_bar-only step metrics with on_epoch=True in hooks that forbid it; refactoring logging calls between hooks without adjusting flags.

Related errors


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