Unexpected broken pipe errors in the JupyterLab terminal

I sometimes get this type of error when using the JupyterLab terminal:

user@host:~/ls20-21$ yes | head
y
y
y
y
y
y
y
y
y
y
yes: standard output: Broken pipe

I only see it in JupyterLab sessions started with JupyterHub + SystemdSpawner, which led me to asking a question here, in the hopes that someone else might have seen this behavior, or might at least have ideas on what might be causing it and what to investigate. Googling led me to this; the only reply sounds somewhat promising, except it refers to Jupyter Notebook (not JupyterLab) and Python 2, and the suggested fix doesn’t seem to work unfortunately.

I’ve never seen this error happen in a regular terminal, in an SSH session on the same system or elsewhere for that matter. And if I SSH into the same system, run jupyter lab on the command line and access JupyterLab via port forwarding, I don’t encounter it either. Which is what led me to suspect JupyterHub / SystemdSpawner.

Another weird thing is that it only seems to happen in bash, I haven’t seen it in fish or zsh (yet?). Also, it’s not like head always causes it, e.g. grep --help | head runs fine, but yes | head has reproduced consistently so far.

The plot thickens: in a bash shell nested inside the original bash shell launched by the JupyterLab terminal, the error is still there. But in a bash shell nested inside a fish shell nested inside the original bash shell, it goes away!

Getting warmer: it looks like systemd is configured to ignore SIGPIPE by default, which is where child processes inherit it from, ultimately causing yes to ignore SIGPIPE from trying to write to head’s closed STDIN and crashing with an error instead of just being killed silently (this is a summary of this SO post).

I’m not quite sure whether I should enable SIGPIPE in my own systemd service that runs JupyterHub, that sounds like maybe not a good idea since it’s probably disabled by default for a reason? Here’s a quote from the first link above:

SIGPIPE is primarily something to ripple up shell pipelines right to
left, if something dies. EOF is usually used from left-to-right. That’s
not really useful for normal daemons though, and as we try to provide a
good, useful execution environment for daemons, we turn this off. Of
course, shells should and suchlike should turn this on again.

Which sounds like maybe re-enabling SIGPIPE should be left to the spawner, or maybe even to the JupyterLab terminal process which fires up the shell?

(grep --help | head is presumably fine because the output of grep --help is small enough that it fits into head's read buffer, so that all of it is read before the pipe is closed?)

Happy to report (largely to myself, AFAICS, but maybe someone will find it useful in the future) that I have a fix! I’ll try to get it upstreamed.

1 Like

Fix merged upstream and released in terminado 0.9.3.

Thank you very much for tracking this down publicly and contributing a fix!

1 Like