{"record":{"id":"993a863f152ed76e","repo":"Lightning-AI/pytorch-lightning","slug":"f-you-can-t-self-log-inside-fx-name-hint","errorCode":null,"errorMessage":"f\"You can't `self.log()` inside `{fx_name}`. HINT: You can still log directly to the logger by using\" \" `self.logger.experiment`.\"","messagePattern":"f\"You can't `self\\.log\\(\\)` inside `(.+?)`\\. HINT: You can still log directly to the logger by using\" \" `self\\.logger\\.experiment`\\.\"","errorType":"validation","errorClass":"MisconfigurationException","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/trainer/connectors/logger_connector/fx_validator.py","lineNumber":161,"sourceCode":"        \"configure_callbacks\": None,\n        \"on_validation_model_zero_grad\": None,\n        \"on_validation_model_eval\": None,\n        \"on_test_model_eval\": None,\n        \"on_validation_model_train\": None,\n        \"on_test_model_train\": None,\n    }\n\n    @classmethod\n    def check_logging(cls, fx_name: str) -> None:\n        \"\"\"Check if the given hook is allowed to log.\"\"\"\n        if fx_name not in cls.functions:\n            raise RuntimeError(\n                f\"Logging inside `{fx_name}` is not implemented.\"\n                \" Please, open an issue in `https://github.com/Lightning-AI/pytorch-lightning/issues`.\"\n            )\n\n        if cls.functions[fx_name] is None:\n            raise MisconfigurationException(\n                f\"You can't `self.log()` inside `{fx_name}`. HINT: You can still log directly to the logger by using\"\n                \" `self.logger.experiment`.\"\n            )\n\n    @classmethod\n    def get_default_logging_levels(\n        cls, fx_name: str, on_step: Optional[bool], on_epoch: Optional[bool]\n    ) -> tuple[bool, bool]:\n        \"\"\"Return default logging levels for given hook.\"\"\"\n        fx_config = cls.functions[fx_name]\n        assert fx_config is not None\n        on_step = fx_config[\"default_on_step\"] if on_step is None else on_step\n        on_epoch = fx_config[\"default_on_epoch\"] if on_epoch is None else on_epoch\n        return on_step, on_epoch\n\n    @classmethod\n    def check_logging_levels(cls, fx_name: str, on_step: bool, on_epoch: bool) -> None:\n        \"\"\"Check if the logging levels are allowed in the given hook.\"\"\"","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/trainer/connectors/logger_connector/fx_validator.py#L143-L179","documentation":"_FxValidator.functions maps each hook to either a config dict (logging allowed with constraints) or None (logging forbidden). When self.log() is called inside a hook whose entry is None — typically hooks that run outside the metric-collection machinery like on_train_start or configure_optimizers — this MisconfigurationException is raised.","triggerScenarios":"Calling self.log('foo', x) inside hooks like on_train_start, on_train_epoch_start, setup, configure_optimizers, or on_test_end, whose registry value is None; also custom hooks invoked with those fx_names.","commonSituations":"Logging an epoch-start summary or learning-rate diagnostics in on_train_start via self.log; migrating code that used experiment.log_metric before; logging in teardown for final aggregates.","solutions":["Log directly to the logger backend instead: self.logger.experiment.add_scalar('foo', x) (TensorBoard) or self.logger.experiment.log_metric(...) (MLflow/W&B)","Move the logging into an allowed hook such as training_step or validation_step (optionally accumulated)","For scalars like LR, prefer self.log('lr', ..., on_step=True) inside training_step rather than on_train_start"],"exampleFix":"# before\ndef on_train_start(self, trainer, pl_module):\n    self.log('epoch', 0)\n\n# after\ndef on_train_start(self, trainer, pl_module):\n    trainer.logger.experiment.add_scalar('epoch', 0, 0)","handlingStrategy":"fallback","validationCode":"from lightning.pytorch.trainer.connectors.logger_connector.fx_validator import _FxValidator\n\nif _FxValidator.functions.get(hook_name) is None:\n    use_logger_experiment()  # do not call self.log here","typeGuard":"def can_self_log(hook_name: str) -> bool:\n    from lightning.pytorch.trainer.connectors.logger_connector import fx_validator\n    cfg = fx_validator._FxValidator.functions.get(hook_name)\n    return cfg is not None","tryCatchPattern":"try:\n    self.log(name, value)\nexcept MisconfigurationException:\n    self.logger.experiment.add_scalar(name, value)","preventionTips":["Remember: self.log only works in *_step hooks and a few others; lifecycle hooks are off-limits","Use callbacks writing to trainer.logger.experiment for epoch/start/end logging","Write a tiny unit test that exercises each self.log call in an epoch"],"tags":["pytorch-lightning","logging","hook-validation","misconfiguration"],"backgroundTag":"logging-in-forbidden-hook","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}