Skip to content

fix(export): force vis=False so export runs headless - #156

Merged
KraHsu merged 1 commit into
devfrom
fix/export-headless-vis
May 24, 2026
Merged

KraHsu merged 1 commit into
devfrom
fix/export-headless-vis

Conversation

@KraHsu

@KraHsu KraHsu commented May 24, 2026

Copy link
Copy Markdown
Owner

Problem

genelab export <trainable-task> <ckpt> -f torchscript|onnx crashes on any
display-less machine (CI / remote server) with:

genesis.GenesisException: No display detected. Use `show_viewer=False` for headless mode.

and there's no CLI override to disable the viewer (No such option: --env.simulation.vis).

Root cause

export_task (src/genelab/cli/_export.py) resolves the play env via
resolve_env_cfg(task_id, play=True). Trainable tasks set simulation.vis=play
(e.g. examples/inverted_pendulum/.../env_cfg.py), so the play env has the
viewer on. interactive_scene.py:198 wires show_viewer=self._sim_cfg.vis, so
building that env on a machine with no display raises. Export only probes obs
shapes — it never renders — so it must force the viewer off, exactly as
eval_task already does (eval_task.py:74, "eval is always headless").

Fix

Set env_cfg.simulation.vis = False right after resolving the env cfg in
export_task. The episode_length_s > 30 clamp eval_task applies is not
needed here — export collects no episodes (verified).

Test

Adds tests/test_export.py::test_export_task_forces_headless_vis: drives the
real export_task with env resolution/build monkeypatched out (no Genesis
runtime, no display), starting from a fake play env cfg with vis=True, and
asserts (a) the cfg handed to build_env has vis is False and (b) the real
exporter produces the .ts + .metadata.json.

tests/test_export.py — 7 passed; ruff clean + formatted.

Reference audit

find_referencing_symbols(export_task) → only caller is
src/genelab/cli/__init__.py::export_cmd (line 394/397). The change adds a line
inside the function body; no symbol renamed/removed, no caller affected.

Verification gap (please confirm on H100/H200)

This change targets the exact vis -> show_viewer knob and mirrors the proven
eval_task approach. I could not fully reproduce the original crash on the
dev box because it has libEGL + offscreen Qt (env build succeeds even with
vis=True). A real genelab export run got past env build headless, then
failed on an unrelated rsl_rl did not expose an actor module (the local
inverted-pendulum checkpoints look like smoke artifacts) — so no green .ts was
produced end-to-end locally. Please run, with a good checkpoint:

QD_GRAPH=0 QT_QPA_PLATFORM=offscreen genelab export GeneLab-Inverted-Pendulum-v0 <ckpt> -f torchscript --out /tmp/p.ts

🤖 Generated with Claude Code

`genelab export <trainable-task>` builds the play env via
`resolve_env_cfg(task_id, play=True)`, and trainable tasks set
`simulation.vis=play` so their play_env opens the viewer. Export only probes
obs shapes — it never renders — so on a display-less CI / server building that
env raised `GenesisException: No display detected`, with no CLI override to
disable it.

Force `env_cfg.simulation.vis = False` right after resolving, mirroring what
`eval_task` already does ("eval is always headless"). The `episode_length_s`
clamp eval applies is not needed here: export collects no episodes.

Add a regression test that drives the real `export_task` with env build
monkeypatched out (no Genesis runtime) and asserts the cfg handed to
`build_env` has the viewer off and the .ts + .metadata.json are produced.
@KraHsu
KraHsu merged commit 2d82c16 into dev May 24, 2026
3 checks passed
@KraHsu
KraHsu deleted the fix/export-headless-vis branch May 24, 2026 07:05
KraHsu added a commit that referenced this pull request Jun 5, 2026
fix(export): force vis=False so export runs headless
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant