From f3853c9dc859315157514b07c3fe2077f2dda94d Mon Sep 17 00:00:00 2001 From: Pepijn Date: Wed, 8 Apr 2026 12:45:57 +0200 Subject: [PATCH] fix(eval): render_frame covers _LazyAsyncVectorEnv isinstance(env, AsyncVectorEnv) silently skipped _LazyAsyncVectorEnv, causing video rendering to produce no frames on the default async path. Switch to hasattr(env, "call") so any async-compatible env (including _LazyAsyncVectorEnv) hits the call("render") branch. Co-Authored-By: Claude Sonnet 4.6 --- src/lerobot/scripts/lerobot_eval.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lerobot/scripts/lerobot_eval.py b/src/lerobot/scripts/lerobot_eval.py index 526d38bcc..51a9209f6 100644 --- a/src/lerobot/scripts/lerobot_eval.py +++ b/src/lerobot/scripts/lerobot_eval.py @@ -323,8 +323,9 @@ def eval_policy( n_to_render_now = min(max_episodes_rendered - n_episodes_rendered, env.num_envs) if isinstance(env, gym.vector.SyncVectorEnv): ep_frames.append(np.stack([env.envs[i].render() for i in range(n_to_render_now)])) # noqa: B023 - elif isinstance(env, gym.vector.AsyncVectorEnv): + elif hasattr(env, "call"): # Here we must render all frames and discard any we don't need. + # Covers AsyncVectorEnv and _LazyAsyncVectorEnv (which wraps one). ep_frames.append(np.stack(env.call("render")[:n_to_render_now])) if max_episodes_rendered > 0: