Host
Host OS: macOS 26.5.2
Host CPU: aarch64 (Apple Silicon)
zig version: 0.16.0
elixir -v: Elixir 1.20.3 (compiled with Erlang/OTP 29)
Burrito: 1.6.0 (Hex)
Target
Same as host.
Found while packaging a terminal UI app (OTP 28+ raw mode). Related to #215 but independent of it: this reproduces with a fully working ERTS supplied via custom_erts (the workaround from #215). Both problems must be fixed for interactive/TUI apps to work in a Burrito binary.
Cause
The EPIPE fix from #225 makes the Unix wrapper spawn the BEAM with its stdout as a pipe, copied to the real stdout by a thread (src/erlang_launcher.zig, .stdout = .pipe + stdoutCopyThread):
The wrapper now pipes child stdout through itself via a copy thread; when the downstream pipe breaks (EPIPE on write), the copy thread kills the child process
The BEAM therefore sees a pipe on stdout even when the user runs the binary in a terminal. OTP's prim_tty requires both stdin and stdout to be TTYs, so the tty backend is disabled entirely.
Symptoms
Probe run from Application.start/2, binary launched in a real terminal, ERTS = local OTP 29 root via custom_erts (so #215 is out of the picture):
| probe |
stock 1.6.0 (stdout piped) |
stdout inherited (local patch) |
:io_ansi.enabled() (OTP 29) |
false |
true |
:shell.start_interactive({:noshell, :raw}) |
{:error, :enotsup} |
:ok |
:io.columns() (after raw) |
{:error, :enotsup} |
{:ok, 80} |
:io.get_chars(:standard_io, "", 1) |
never returns — keyboard input is never delivered |
{:ok, "x"} |
Plain writes still pass through the copy thread, so an app can draw — it just can't detect the terminal, enter raw mode, query the size, or read a single keystroke. With stdout inherited, a full TUI (alternate screen, raw keyboard input, mouse reporting) works end to end in the Burrito binary.
Suggested fix
Only interpose the pipe when it's needed: check isatty(STDOUT_FILENO) in the wrapper.
Windows already inherits stdout, so this would also re-unify behavior across platforms. Happy to test a patch.
Host
Host OS: macOS 26.5.2
Host CPU: aarch64 (Apple Silicon)
zig version:0.16.0elixir -v:Elixir 1.20.3 (compiled with Erlang/OTP 29)Burrito:
1.6.0(Hex)Target
Same as host.
Found while packaging a terminal UI app (OTP 28+ raw mode). Related to #215 but independent of it: this reproduces with a fully working ERTS supplied via
custom_erts(the workaround from #215). Both problems must be fixed for interactive/TUI apps to work in a Burrito binary.Cause
The EPIPE fix from #225 makes the Unix wrapper spawn the BEAM with its stdout as a pipe, copied to the real stdout by a thread (
src/erlang_launcher.zig,.stdout = .pipe+stdoutCopyThread):The BEAM therefore sees a pipe on stdout even when the user runs the binary in a terminal. OTP's
prim_ttyrequires both stdin and stdout to be TTYs, so the tty backend is disabled entirely.Symptoms
Probe run from
Application.start/2, binary launched in a real terminal, ERTS = local OTP 29 root viacustom_erts(so #215 is out of the picture)::io_ansi.enabled()(OTP 29)falsetrue:shell.start_interactive({:noshell, :raw}){:error, :enotsup}:ok:io.columns()(after raw){:error, :enotsup}{:ok, 80}:io.get_chars(:standard_io, "", 1){:ok, "x"}Plain writes still pass through the copy thread, so an app can draw — it just can't detect the terminal, enter raw mode, query the size, or read a single keystroke. With stdout inherited, a full TUI (alternate screen, raw keyboard input, mouse reporting) works end to end in the Burrito binary.
Suggested fix
Only interpose the pipe when it's needed: check
isatty(STDOUT_FILENO)in the wrapper.app | head -5) cannot occur on a tty.Windows already inherits stdout, so this would also re-unify behavior across platforms. Happy to test a patch.