systemd networkd wait online failed — the 2-minute boot tax
Not a broken network — a fuse with no limit. Measured: one dead link parks boot at 2min 10.7s; a 5s bound costs nothing and keeps the promise.
Why did systemd networkd wait online fail?
Because wait-online's whole job is waiting for a promise, and one interface had made a promise it couldn't keep. The bench armed a dummy interface — a link with no peer, no cable, no carrier — set to DHCP=yes and RequiredForOnline=yes. systemd-networkd held it in configuring forever: DHCP asked, nobody answered. And wait-online refused to declare the network online while it configured.
The claim sentence: wait-online fails when an interface can't reach its RequiredForOnline state — and at defaults, it holds the whole boot until its own fuse burns. The journal receipt, start to exit:
systemd[1]: Starting Wait for Network to be Online...
systemd-networkd-wait-online[420]: Timeout occurred while waiting for network connectivity.
systemd[1]: systemd-networkd-wait-online.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: systemd-networkd-wait-online.service: Failed with result 'exit-code'.
systemd[1]: Failed to start Wait for Network to be Online.
verify: the run spans 05:15:57.247 → 05:17:57.407 — 2min 0.16s, exit 1, on a box where the only wrong thing was one dead link.
Note who lit that fuse: not systemd's generic start-timeout (TimeoutStartUSec=infinity — the unit asks for none), and not the cable. On this build the service carries its own internal give-up at the two-minute mark, exits 1, and systemd marks the unit failed. Until that moment boot sat behind it: multi-user.target @2min 7.483s, with sshd — and everything after it — queued on the wait.
Result=timeout, dependents start at most 5s lateWhat does the screen say while it fails?
The famous line, captured off the console during the run:
[ * ] (1 of 2) A start job is running for…twork to be Online (7s / no limit)
verify: the suffix is the fuse — (7s / no limit) means systemd was never given a time to give up. The ellipsis is the console truncating Wait for Network to be Online; the counter is the job's seconds alive.
That no limit is the trap. A boot stuck on this job has no scheduled end — a counter with no ceiling on a black screen, which is why the "2 minutes, every boot" reports all sound the same. On the bench box the counter ended at 2min 0.16s, when the service's internal fuse finally fired.
Is it safe to disable?
Cure one, measured. sudo systemctl disable systemd-networkd-wait-online.service — one symlink out of network-online.target.wants/ — and the same boot ran 42.613s, userspace included. Nothing broke, nothing hung: on this VM nothing ordered itself after network-online.target except cloud-init's network stage, which simply started at 6.5s instead of 2min 7.3s.
What you give up is the ordering promise: services with After=network-online.target — NFS mounts, some VPN and backup daemons — start before the network is truly ready. Audit before you cut:
grep -rl "network-online.target" /etc/systemd/system/
verify: no output = nothing on this box waits on the promise; disabling is free.
This family has a twin — September's systemd service not starting: the log already named the cause met the NetworkManager cousin, NetworkManager-wait-online.service, in one verify line. Same habit, different network manager: the wait service ships enabled, and nobody remembers why.
How do I bound the wait to 5 seconds?
Cure two keeps the promise and prices it. A drop-in caps the service's start time:
sudo systemctl edit systemd-networkd-wait-online.service
# in the editor:
[Service]
TimeoutStartSec=5s
verify: systemctl show systemd-networkd-wait-online.service -p TimeoutStartUSec prints 5s.
Reboot with the same dead link aboard: boot ran 42.986s — 0.4s slower than disabled, 88s faster than default. The service died on schedule, with its own receipt:
systemd[1]: systemd-networkd-wait-online.service: start operation timed out. Terminating.
systemd[1]: systemd-networkd-wait-online.service: Failed with result 'timeout'.
The ordering promise survives in bounded form: dependents start at most 5s late — cloud-init's network stage ran at 11.9s here, vs 6.5s disabled — and a healthy network costs nothing, because wait-online exits the moment every interface is online. That's the trade in one line: the bound turns an unbounded tax into a fixed 5-second worst case.
Which door should you pick?
| door | boot on a dead link | the cost |
|---|---|---|
| leave it (default) | 2min 10.7s | no scheduled exit — every dead link bills the full wait, every boot |
| disable the service | 42.6s | no network-online ordering for anything that asks |
| bound it to 5s (drop-in) | 43.0s | dependents start ≤5s late; ends Result=timeout while the link is dead |
| fix the dead link | clean boot | the only door that keeps the full promise — requires finding it (next section) |
How do I find the link it's stuck on?
wait-online won't name the culprit. networkctl will:
networkctl status LINK --no-pager
# the dead link on the bench box read:
# State: degraded (configuring)
verify: a healthy link prints configured / routable; a link parked in configuring is the one billing your boot.
Then judge it: a leftover interface from a VM migration, a typo'd name in /etc/systemd/network/, a bond member that never came up. Either give it a network, or stop asking it for one — RequiredForOnline=no in its .network file keeps the link and shrinks the promise to the interfaces that can keep it.
The cure, in order
"wait-online doesn't wait for the network. It waits for a promise the network never made — and boot pays by the minute."
what the bench did not cover
Measured: one dead dummy link with DHCP=yes + RequiredForOnline=yes, three configs, one fresh Arch VM, systemd 262, wired emulated ethernet. Not measured: the --any flag (wait for ANY interface instead of all — a different promise), multi-interface boxes where one good link could satisfy a relaxed policy, wireless roaming flaps, and host-side veth timing under containers. The internal two-minute give-up is this build's behavior — read your own fuse with systemctl show systemd-networkd-wait-online.service -p TimeoutStartUSec before quoting it.
HUMAN-VERIFIED BENCH · systemd 262 · fresh Arch VM · last tested 2026-11-10
The boot tax collector never sends a bill — just a counter with no ceiling on a black screen. Set the fuse, or fix the link. ■