fordelkon
### Bug description `RichProgressBar` renders a **stale-metrics frame** at the end of every validation epoch. The refresh fired in the callback's `on_validation_epoch_end` re-renders the metrics column, but the column's cache (`MetricsTextColumn._metrics`) is only updated by `_update_metrics` — called at `on_train_batch_end`, `on_train_epoch_end` and `on_validation_end`, **not** at `on_validation_epoch_end`. The frame therefore shows the **previous** epoch's validation values. `on_validation_end` then updates the column and the final render shows fresh values — producing two near-identical bar lines with **different metric values**, with no indication which one is final. Note: `trainer.progress_bar_metrics` is already up to date at that moment — only the column's own cache is stale, so this is purely a display-layer issue and the fix is to refresh the column (call `_update_metrics`) before that render. ### What version are you seeing the problem on? v2.6 ### Reproduced in studio _No response_ ### How to reproduce the bug ```python import torch import lightning as L from lightning.pytorch.callbacks import RichProgressBar from torch.utils.data import DataLoader, TensorDataset class BoringModel(L.LightningModule): def __init__(self): `RichProgressBar` renders a **stale-metrics frame** at the end of every validation epoch. The refresh fired in the callback's `on_validation_epoch_end` re-renders the metrics column, but the column's cache (`MetricsTextColumn._metrics`) is only updated by `_update_metrics` — called at `on_train_batch_end`, `on_train_epoch_end` and `on_validation_end`, **not** at `on_validation_epoch_end`. The frame therefore shows the **previous** epoch's validation values. `on_validation_end` then updates the column and the final render shows fresh values — producing two near-identical bar lines with **different metric values**, with no indication which one is final. Note: `trainer.progress_bar_metrics` is already up to date at that moment — only the column's own cache is stale, so this is purely a display-layer issue. ### How to reproduce The model logs a per-epoch marker (`val/marker` = current epoch), so every render is self-identifying — no numeric coincidence can mask the staleness: ```python import torch import lightning as L from lightning.pytorch.callbacks import RichProgressBar from torch.utils.data import DataLoader, TensorDataset class BoringModel(L.LightningModule): def __init__(self): super().__init__() self.layer = torch.nn.Linear(2, 2) def training_step(self, batch, idx): self.log("train/loss", self.layer(batch[0]).sum(), prog_bar=True) return self.layer(batch[0]).sum() def validation_step(self, batch, idx): self.log("val/marker", float(self.current_epoch), on_epoch=True, prog_bar=True) def configure_optimizers(self): return torch.optim.SGD(self.parameters(), lr=0.1) class DebugBar(RichProgressBar): def on_validation_epoch_end(self, trainer, pl_module): print("rendered column:", self._metric_component._metrics, "| live pbar metrics:", trainer.progress_bar_metrics) super().on_validation_epoch_end(trainer, pl_module) trainer = L.Trainer(max_epochs=3, callbacks=[DebugBar()], logger=False, enable_checkpointing=False, enable_model_summary=False) trainer.fit(BoringModel(), train_dataloaders=DataLoader(TensorDataset(torch.randn(8, 2)), batch_size=4), val_dataloaders=DataLoader(TensorDataset(torch.randn(8, 2)), batch_size=4)) ``` While validating epoch N ≥ 1, the printed rendered column shows `val/marker: N-1` (the previous epoch), while the live metrics already hold `N`. ### Environment <details> <summary>Current environment</summary> ``` - Lightning 2.6.6 - PyTorch 2.14.0 - Python 3.12 - Windows 11 (logic is OS-independent) ``` </details> ### More info ### Root cause In `lightning/pytorch/callbacks/progress/rich_progress.py` (2.6.6), `on_validation_epoch_end` (≈ L528-532) hides the val task and forces a full `self.refresh()` without calling `_update_metrics` first — the metrics column cache is only refreshed at `on_train_batch_end` / `on_train_epoch_end` / `on_validation_end`. ### Expected behavior The frame that hides the validation row should not present stale epoch metrics as if current — either call `_update_metrics` before the refresh (the underlying `progress_bar_metrics` is already current), or suppress the metrics column on that frame. cc @ethanwharris