Copy in Lazygit when using SSH
Copy in Lazygit when using SSH
When using Lazygit on a headless server (no screen, no X11/Wayland) over SSH, pressing y to copy (e.g. copying a commit hash, file name…) will produce this error:
Error
write |1: broken pipe
Root cause
Lazygit copies data to the clipboard by calling an external system clipboard program such as xclip, xsel (X11) or wl-copy (Wayland), then writes the data into that program’s stdin.
On a headless server:
- There is no
$DISPLAYor$WAYLAND_DISPLAYenvironment variable. - The
xclip/xsel/wl-copycommands cannot connect to a display server, so they exit immediately. - Lazygit still tries to write data into the stdin of the already-exited process → the pipe is closed → error
write |1: broken pipe.
Solution: use OSC 52
OSC 52 is an escape sequence that allows a program inside a terminal to send data straight into the local machine’s clipboard (the machine you SSH from), without needing a clipboard backend on the server. It is supported by modern terminals: iTerm2, kitty, WezTerm, Windows Terminal, newer Alacritty, and more.
Step 1 — Find the config directory
lazygit -cd
(prints the config directory, e.g. /root/.config/lazygit)
Step 2 — Write the OSC 52 config into config.yml
cat > "$(lazygit -cd)/config.yml" << 'EOF'
os:
copyToClipboardCmd: "printf '\x1b]52;c;%s\a' \"$(cat {{filename}} | base64 | tr -d '\n')\""
EOF
Important note: use \x1b (hex escape) and not \033 (octal escape). YAML only supports hex/unicode escapes, not octal. If you use \033, YAML will misinterpret it as the character \0 (NUL) followed by 33, inserting a null byte into the command string, causing Go’s exec to fail:
fork/exec /bin/bash: invalid argument
(because the command string contains a NUL byte — which C strings / exec do not permit).
Step 3 — Restart Lazygit and try copying
Open Lazygit again, press y on the commit or file you want to copy. The content will be sent directly to your local machine’s clipboard via the terminal.
Notes for tmux/screen users
If you run Lazygit inside tmux, the OSC 52 escape sequence may be blocked in transit. Enable:
set -g set-clipboard on
in ~/.tmux.conf, or configure pass-through separately depending on your tmux version.
Notes for Herdr users
Herdr is a terminal workspace manager for AI coding agents, and it also acts as an intermediate terminal layer. When Lazygit runs inside Herdr, the OSC 52 sequence must pass through Herdr before being forwarded to the host’s real terminal.
This is a known bug in Herdr itself (issue #2399): when copying content from an application running inside Herdr, the “copied to clipboard” message still appears, but the content does not actually reach the system clipboard — pasting (Ctrl+V) still shows the old content. This bug only occurs when Herdr runs in default (local) mode; when running with herdr --remote, clipboard works normally.
Workaround: start Herdr with the --remote flag:
herdr --remote
The copyToClipboardCmd configuration in Lazygit (as described above) is still correct and necessary — the issue lies in Herdr not forwarding OSC 52 to the outer terminal when running locally, not in Lazygit or the YAML config.
Summary
| Error / Symptom | Root cause |
|---|---|
write |1: broken pipe |
No clipboard backend (xclip/wl-copy) on a headless server — no display server |
fork/exec /bin/bash: invalid argument |
Using \033 (octal) in a YAML double-quoted string → NUL byte in the command string, Go exec rejects it |
| Copy reports success but host clipboard doesn’t receive it | Running inside Herdr in local mode — Herdr doesn’t forward OSC 52 to the outer terminal (needs herdr --remote) |
General solution: configure copyToClipboardCmd to use OSC 52 (\x1b]52;c;...) to send clipboard data through the terminal, independent of GUI/display server on the remote machine.