From 2f2e42c4aa0d2c3f42b335db9daeea02e0fb39ca Mon Sep 17 00:00:00 2001 From: Pepijn Date: Thu, 30 Apr 2026 13:48:02 +0200 Subject: [PATCH] log(annotate): warn loudly on first video decode failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VideoFrameProvider._decode used to swallow every exception silently and return []. That made Module 3 (VQA) produce zero rows whenever local video decoding broke (codec, backend, missing file, ...) because every prompt got skipped via the ``not _has_image_block(messages)`` branch in general_vqa.py — without any signal in the job log. Log the first failure with full exception info (subsequent failures stay quiet to avoid log spam) so this fast-path is debuggable. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../annotations/steerable_pipeline/frames.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/lerobot/annotations/steerable_pipeline/frames.py b/src/lerobot/annotations/steerable_pipeline/frames.py index a2f2e4897..7a37bc2c4 100644 --- a/src/lerobot/annotations/steerable_pipeline/frames.py +++ b/src/lerobot/annotations/steerable_pipeline/frames.py @@ -208,7 +208,25 @@ class VideoFrameProvider: backend=backend, return_uint8=True, ) - except Exception: + except Exception as exc: + # Log loudly the first time decoding fails so silent + # Module-3-no-op (every prompt skipped because frames_at returned + # []) is debuggable from the job log instead of post-hoc parquet + # inspection. Subsequent failures stay quiet. + if not getattr(self, "_warned_decode_fail", False): + import logging # noqa: PLC0415 + + logging.getLogger(__name__).warning( + "VideoFrameProvider._decode failed for episode=%s camera=%s " + "video_path=%s backend=%s: %s", + episode_index, + camera_key, + video_path, + backend, + exc, + exc_info=True, + ) + self._warned_decode_fail = True return [] # frames: [N, C, H, W] uint8, RGB out: list[Any] = []