Troubleshooting
Every symptom here happened in the lab, to the person building it or on purpose. The format is the series' usual: symptom → what it actually means → the fix.
It connects, I send, and then it just sits there
Meaning: the conversation isn't over — your side finished sending but never said goodbye, and the other side is waiting for the rest. Netcat's default is to stay on the line after stdin ends (chapter 9).
Fix: -N on the sending side, so
end-of-input shuts down the socket's
sending half; or -w to bound the
silence. Measured difference: with
-N, exit 0 in 0.0s after input; with
neither, the lab's run was still
sitting there when its lifeguard
pulled it out at 3s — and would be
still.
The command failed and printed nothing at all
Meaning: it didn't fail quietly on
purpose; without -v, this netcat
prints nothing on failure — no
message, just exit 1. A refused
connection, a bad address, and a
mistake all look identical: silence.
Fix: re-run with -v. The failure
names itself:
$ nc -zv 127.0.0.1 45999; echo "exit: $?"
nc: connect to 127.0.0.1 port 45999 (tcp) failed: Connection refused
exit: 1
In scripts, either always use -v and
log stderr, or treat the exit code as
the entire report and design for that
(chapter 7).
The check says timed out — but the service is up
Meaning: silence, the third answer
(chapter 5). Something between you and
the service — usually a firewall doing
DROP, not REJECT — is eating the
packets. The tell is the wait: refused
answers instantly; silence makes you
wait out your whole -w.
Fix: run the same nc -zv from the
service's own machine (loopback). If
it succeeds there and times out from
yours, the service is innocent and the
path is guilty. If you'd run the check
without -w, you'd still be waiting —
the operating system's connect timeout
is minutes long.
My message was sent and nc exited 0, but nothing arrived
Meaning: your bytes were delivered to a socket nobody was reading — the classic case is chapter 4's: the listener was busy with (or still finishing) another caller, your connection waited in its backlog, and the listener quit before accepting you. UDP has the purer version (chapter 8): sending to an empty port exits 0 because UDP cannot know.
Fix: there isn't a flag for "make
sure a program read it" — that
knowledge lives one level up. Have the
receiver acknowledge (a reply, a file,
a log line), or make the receiving side
-k and long-lived enough that "busy"
can't happen. Design scripts to verify
the effect, not the exit code.
The file arrived short — or the receiver's file is empty
Meaning, empty receiver file: the sender never connected (chapter 6's silent exit 1 creates a 0-byte file via your own redirection). Empty means never started, not corrupted.
Meaning, short file: the stream
was cut — sender killed before
finishing, or sent without -N and
someone lost patience with the hang
and Ctrl-C'd whichever side was in
front of them.
Fix: hashes, both ends, every time (chapter 6). If they differ, redo the transfer; netcat has no resume, and a partial file with a confident name is worse than none.
The name resolved and the check "succeeded" — for a host that doesn't exist
Meaning: your resolver is lying to you. The lab's build machine does this:
$ nc -zv no-such-host.invalid 45002; echo "exit: $?"
Connection to no-such-host.invalid (198.18.83.181) 45002 port [tcp/*] succeeded!
exit: 0
$ getent hosts no-such-host.invalid; echo "exit: $?"
198.18.83.181 no-such-host.invalid
exit: 0
The sandbox's resolver answers any
name with an address in a
reserved-for-testing range, and
something there accepts connections.
Real-world versions are commoner than
you'd hope: ISP resolvers that turn
typos into search pages, captive
portals, wildcard DNS on a domain you
typo'd into. Fix: when a result
is too good, check the name
independently (getent hosts,
dig) and distrust any environment
that answers everything — a check
that cannot fail cannot inform.
The Unix socket listener won't start — the path is "in use"
Meaning: chapter 10's leftover — the socket file from the last listener is still on disk, because exiting doesn't remove it.
Fix: rm the stale socket file,
then start the listener. And build the
habit at the source: lab sockets live
in a scratch directory you clean as a
set.
The commands from a tutorial don't work
Meaning: the tutorial's nc isn't
yours. The flag alphabets overlap
without matching — most famously, a
traditional-netcat listener wants
nc -l -p PORT while OpenBSD wants
nc -l HOST PORT, and -N doesn't
exist on the traditional one at all.
Fix: nc -h 2>&1 | head -1 on
the machine in front of you, and
chapter 12's table. Ten seconds of
identification saves the afternoon of
guessing.
Check: each fix above can be rehearsed against the lab in minutes — and the lab is the place to meet these for the first time, rather than at 3 a.m. with a production-shaped socket.