Description
When Evaluate() returns early — between Start() and the Record()/teardown() path — the ttyd process is left running indefinitely.
The deferred cleanup at evaluator.go:45 only calls v.close(), which is set to vhs.browser.Close. The terminate() method that kills both browser and ttyd is only reachable via teardown(), which requires Record() to have started.
Affected code paths
Any early return after Start() succeeds but before Record() begins:
Page.Wait fails (evaluator.go:50-53)
- A
SET command fails (evaluator.go:59-63)
- Video dimensions too small (
evaluator.go:78-91)
- A
Hide block command fails (evaluator.go:106-109)
Additionally, Start() itself doesn't clean up ttyd if browser launch or page creation fails after ttyd is already started.
Reproduction
# Create a tape that triggers an early SET error
echo 'Set Width 0' > /tmp/bad.tape
echo 'Type "hello"' >> /tmp/bad.tape
# Run vhs (it will error due to bad dimensions)
vhs /tmp/bad.tape
# Check for orphaned ttyd
ps aux | grep ttyd
# ttyd process is still running
Expected behavior
All ttyd processes spawned by VHS should be killed when VHS exits, regardless of which code path is taken.
Description
When
Evaluate()returns early — betweenStart()and theRecord()/teardown()path — thettydprocess is left running indefinitely.The deferred cleanup at
evaluator.go:45only callsv.close(), which is set tovhs.browser.Close. Theterminate()method that kills both browser and ttyd is only reachable viateardown(), which requiresRecord()to have started.Affected code paths
Any early return after
Start()succeeds but beforeRecord()begins:Page.Waitfails (evaluator.go:50-53)SETcommand fails (evaluator.go:59-63)evaluator.go:78-91)Hideblock command fails (evaluator.go:106-109)Additionally,
Start()itself doesn't clean up ttyd if browser launch or page creation fails after ttyd is already started.Reproduction
Expected behavior
All
ttydprocesses spawned by VHS should be killed when VHS exits, regardless of which code path is taken.