Copy/paste from a remote SSH session pastes as mojibake (`’`, `Â`, `é`)
Source: Troubleshooting reference
Symptom: text copied out of a remote Linux session pastes with latin-1 garbage
where punctuation, accents, or spaces should be: ’ becomes ’, é becomes
é, non-breaking spaces surface as  . Two common shapes:
- plain ssh + tmux — the display itself is garbled, and copies carry it
- VS Code/Cursor Remote-SSH embedded terminal — display may look fine, but
copying agent TUI output (Claude Code renders with padding/NBSP characters)
pastes with stray
Âaccent characters; no tmux involved
The terminal emulator (iTerm2, xterm.js) is innocent: the bytes are already mangled before they reach it.
Root cause chain:
- On macOS,
.zprofileexportsLC_ALL=en_US.UTF-8 - macOS ships
SendEnv LANG LC_*in/etc/ssh/ssh_config, and Linux sshd acceptsLC_*by default — the Mac’sLC_ALLlands in the remote environment. This covers Remote-SSH too: the VS Code/Cursor server is started over that same ssh connection, and every embedded terminal inherits its environment LC_ALLoverridesLANG, defeating the deliberate LANG-only locale setup in the Linux shell profiles (see the entry above). Embedded terminals are hit hardest: they spawn non-login shells, so a profile-only guard never even runs there- On hosts whose system glibc has no
en_US.UTF-8compiled (minimal server images — the brew-glibcLOCPATHdata doesn’t help system binaries),setlocale()falls back to C/ASCII - Anything in that C locale that re-encodes the byte stream (system tmux is the classic offender) treats each UTF-8 byte as a separate latin-1 character — the display, and therefore anything selected and copied from it, is mojibake
Confirm on the remote, inside the garbling session:
locale; echo "LC_ALL=$LC_ALL"; locale -a 2>/dev/null | grep -iE 'en_US|utf'printf 'caf\xc3\xa9 \xe2\x80\x94 \xe2\x80\x9cok\xe2\x80\x9d\n' # should render: café — “ok”Broken looks like: a “cannot change locale” warning or LC_CTYPE="C" in the
locale output, and the printf line rendering as café — “okâ€.
Fix: the locale guard (unset LC_ALL before exporting LANG, from the
locale-env.sh shared partial) runs in the Linux shell profiles AND the
interactive rc files — the rc copy is what protects non-login embedded
terminals. Then:
chezmoi apply ~/.zprofile ~/.bash_profile ~/.zshrc ~/.bashrctmux kill-server # the tmux server caches the locale it started withexec zsh -l # or reconnect / open a fresh embedded terminalNote the fix cleans the encoding; agent TUIs like Claude Code still put
invisible layout characters (padding spaces, hard wraps) into the scrollback,
so terminal-selection copies of long output stay imperfect. For clean text use
/export or copy from the paired web/mobile session instead.
If it’s still garbled, the host has no UTF-8 locale usable by system binaries at
all — check locale -a; export LANG=C.UTF-8 (built into every modern glibc)
is the fallback.
Note the tempting client-side fix does NOT work: SendEnv -LC_* in
~/.ssh/config is a no-op here, because ssh reads the user config before
/etc/ssh/ssh_config and -pattern removals apply at parse time — the system
default adds the patterns after your removal runs.