{"record":{"id":"dd3773625197f110","repo":"Lightning-AI/pytorch-lightning","slug":"if-lengths-are-passed-len-self-lengths-ther","errorCode":null,"errorMessage":"If lengths are passed ({len(self._lengths)}), there needs to be the same number of samples ({len(self._samples)})","messagePattern":"If lengths are passed \\((.+?)\\), there needs to be the same number of samples \\((.+?)\\)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/lightning/fabric/utilities/throughput.py","lineNumber":164,"sourceCode":"            samples: Total samples seen per device. It should monotonically increase by the batch size with each call.\n            lengths: Total length of the samples seen. It should monotonically increase by the lengths of a batch with\n                each call.\n            flops: Flops elapased per device since last ``update()`` call. You can easily compute this by using\n                :func:`measure_flops` and multiplying it by the number of batches that have been processed.\n                The value might be different in each device if the batch size is not the same.\n\n        \"\"\"\n        self._time.append(time)\n        if samples < batches:\n            raise ValueError(f\"Expected samples ({samples}) to be greater or equal than batches ({batches})\")\n        self._batches.append(batches)\n        self._samples.append(samples)\n        if lengths is not None:\n            if lengths < samples:\n                raise ValueError(f\"Expected lengths ({lengths}) to be greater or equal than samples ({samples})\")\n            self._lengths.append(lengths)\n            if len(self._samples) != len(self._lengths):\n                raise RuntimeError(\n                    f\"If lengths are passed ({len(self._lengths)}), there needs to be the same number of samples\"\n                    f\" ({len(self._samples)})\"\n                )\n        if flops is not None:\n            # sum of flops across ranks\n            self._flops.append(flops * self.world_size)\n\n    def compute(self) -> _THROUGHPUT_METRICS:\n        \"\"\"Compute throughput metrics.\"\"\"\n        metrics = {\n            \"time\": self._time[-1],\n            \"batches\": self._batches[-1],\n            \"samples\": self._samples[-1],\n        }\n        if self._lengths:\n            metrics[\"lengths\"] = self._lengths[-1]\n\n        add_global_metrics = self.world_size > 1","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/fabric/utilities/throughput.py#L146-L182","documentation":"ThroughputMonitor.update() keeps parallel internal lists _samples and _lengths and requires them to stay in lockstep. This RuntimeError fires when lengths was passed on some update() calls but not others, so the list lengths diverge.","triggerScenarios":"Calling throughput.update(..., lengths=None) on some iterations (e.g. only tracking lengths on certain steps or ranks) after having previously passed a non-None lengths value, making len(self._samples) != len(self._lengths).","commonSituations":"Conditional tracking like `if step % 10 == 0: update(..., lengths=...)` else `update(...)` without lengths; a code path where lengths is only computed for variable-length batches; or a version upgrade where lengths tracking was added mid-run.","solutions":["Pass lengths consistently on every update() call (compute it every iteration, defaulting to the batch size if all sequences are equal length)","Or never pass lengths at all if you do not need per-element accounting","Audit all call sites of update() to ensure the lengths argument is not conditionally omitted"],"exampleFix":"# before\nlengths = total_tokens if variable else None\nthroughput.update(batch=b, samples=n, lengths=lengths)\n\n# after\nlengths = total_tokens if variable else n  # always a value\nthroughput.update(batch=b, samples=n, lengths=lengths)","handlingStrategy":"validation","validationCode":"def safe_update(mon, **kw):\n    has_lengths = len(mon._lengths) > 0\n    if has_lengths and kw.get('lengths') is None:\n        kw['lengths'] = kw['samples']  # fall back to samples count\n    mon.update(**kw)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Decide up front whether you track lengths and stick to it for every update call","Wrap update() in one helper so the lengths argument cannot diverge across call sites"],"tags":["pytorch-lightning","throughput","state-consistency"],"backgroundTag":"inconsistent-state-update","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}