Skip to content

Troubleshooting

Scope: the failures rsync actually produces, in its own words — every message below was generated in the lab while building this guide.

rsync's exit code is the first diagnostic. Zero is a clean run; anything else is a specific complaint. The codes in this chapter: 23 (some files not transferred), 24 (files vanished mid-run), 25 (the --max-delete limit stopped deletions), 20 (interrupted by a signal), 12 (the protocol never got started).

Symptom → "some files/attrs were not transferred" (code 23)

symlink has no referent: "/home/.../err-src/broken.txt"
...
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1356) [sender=3.2.7]

Code 23 is a bucket: something in the list couldn't be transferred, everything else was, and the lines above the summary name the casualties. The lab produced it with a dangling symlink copied under -L (follow links): there was nothing at the other end of the link to send. The same code covers unreadable files (permissions) and, in the network chapter, a daemon that couldn't open its own module's files:

rsync: [sender] send_files failed to open "hello.txt" (in demo): Permission denied (13)

Fix: read upward, not the summary. For permission denials, check the whole path — the daemon case was a parent directory the daemon's user couldn't traverse, not the file's own mode.

Symptom → "some files vanished before they could be transferred" (code 24)

file has vanished: "/home/.../vanish-src/f25.bin"
rsync warning: some files vanished before they could be transferred (code 24) at main.c(1356) [sender=3.2.7]

The file was there when rsync built its list and gone when its turn came — deleted, rotated, or still being written by something else. In the lab the file was removed mid-run on purpose; the other 39 of 40 files arrived. Code 24 is a warning class: the run completed, and one source was a moving target.

Fix: usually none, or sync a quieter tree — snapshot the source first (a filesystem snapshot, or a copy made when the writer is idle) if the tree is busy. Treat 24 as fatal only if your scripts must, and know that log directories and mail spools produce it innocently all the time.

Symptom → the remote side never starts (code 12)

bash: line 1: /nonexistent/rsync: No such file or directory
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(232) [sender=3.2.7]

Over a remote shell, rsync must run on both ends. The remote shell's own error line — here a deliberately wrong path — is the real message; the code-12 line just says the protocol stream died. The everyday version reads rsync: command not found (documented phrasing — the shell's, so it varies): rsync isn't installed on the far side, or isn't on the login shell's PATH.

Fix: install rsync remotely, or point --rsync-path at where it lives. Diagnose with the shell alone: ssh host 'which rsync' must succeed before rsync-over-ssh can.

Symptom → the run stops dead (code 20)

rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20)

Somebody interrupted it — Ctrl-C, a closed terminal, a killed script. Nothing here is corrupt: completed files are complete, in-progress files are not (that's the state --partial exists to improve — see How rsync Decides What to Send). Re-run the same command; the quick check skips everything already done.

Symptom → files arrive with wrong owners or modes

Causes, in the order to check them: -a wasn't used (plain -r drops times and permissions by design); the destination filesystem can't represent them (a FAT stick has no Unix modes to preserve — the sync "works" and the metadata silently doesn't (documented)); the copy was made as a different user than the one that reads it; or the daemon's uid/gid settings are doing exactly what they say. stat one file on both sides and compare — the mismatch is always visible in one look.

Symptom → the copy works here, fails on a case-insensitive destination

A tree containing both Readme.txt and README.txt is legal on Linux and a collision on default macOS and Windows filesystems: the two names fight over one destination file, and the "sync" churns or loses one (documented — the lab's filesystem is case-sensitive, so this couldn't be produced there). Fix: rename on the source; no rsync option reconciles names the destination can't distinguish.

Symptom → it re-copies everything, every time

The quick check is failing open. Almost always: timestamps aren't being preserved (no -t, so not using -a), or the destination clock/format can't hold them (some network filesystems round times — --modify-window=2 is the documented tolerance for exactly that (documented)). One itemised dry run shows it: every file listed as changed, every run. Compare one file's times with stat on both sides; they will not match, and the reason is one of the two above.