Piping logs/JSON to a consumer that exits triggers Broken pipe and CLI panic.
Repro
tower apps logs <app>#<run> | head -n 1tower apps show --json | head -n 1
Expected
- CLI exits cleanly (exit code 0), no panic.
Actual
- CLI panics on
Broken pipe.
Sample reproducible job
tower run --dir tower-examples/pressure-logs -p LINES=5000 -p LINE_BYTES=200 --detached- wait a few seconds
tower apps logs pressure-logs#<run> | head -n 1
Sample script
importjsonimportosimportsysdefto_int(value, name):
try:
returnint(value)
exceptValueError:
print(f"Invalid integer for {name}: {value}")
sys.exit(2)
defmain():
lines=to_int(os.environ.get("LINES", "0"), "LINES")
line_bytes=to_int(os.environ.get("LINE_BYTES", "0"), "LINE_BYTES")
payload="x"*max(0, line_bytes-80)
foridxinrange(1, lines+1):
record= {"seq": idx, "payload": payload}
print(json.dumps(record, separators=(",", ":")))
print("LOG_DONE")
if__name__=="__main__":
main()Sample output
`thread 'main' panicked at crates/tower-cmd/src/output.rs:213:48:`
`called Result::unwrap() on an Err value: Os { code: 32, kind: BrokenPipe, ... }`
Piping logs/JSON to a consumer that exits triggers
Broken pipeand CLI panic.Repro
tower apps logs <app>#<run> | head -n 1tower apps show --json | head -n 1Expected
Actual
Broken pipe.Sample reproducible job
tower run --dir tower-examples/pressure-logs -p LINES=5000 -p LINE_BYTES=200 --detachedtower apps logs pressure-logs#<run> | head -n 1Sample script
Sample output