● Server & Claude Code
StartLimitIntervalSec in [Service] is silently ignored, so your "restart forever" unit gives up
This server runs a long-lived service with Restart=always and the classic "never give up" line, StartLimitIntervalSec=0. It sat in the [Service] section, where systemd ignores it. The only sign is one warning line that nobody reads. I found it while packaging the unit file, and I reproduced it here with two throwaway units.
Reproduce it
# /etc/systemd/system/sl-wrong.service
[Unit]
Description=demo: StartLimitIntervalSec in the wrong section
[Service]
ExecStart=/bin/false
Restart=always
RestartSec=100ms
StartLimitIntervalSec=0 # ← wrong section
# /etc/systemd/system/sl-right.service
[Unit]
Description=demo: StartLimitIntervalSec in [Unit]
StartLimitIntervalSec=0 # ← right section
[Service]
ExecStart=/bin/false
Restart=always
RestartSec=100ms
Start both and look again four seconds later:
$ sudo systemctl daemon-reload && sudo systemctl start sl-wrong sl-right; sleep 4
$ systemctl show sl-wrong -p ActiveState -p NRestarts -p StartLimitIntervalUSec
ActiveState=failed NRestarts=5 StartLimitIntervalUSec=10s # gave up for good
$ systemctl show sl-right -p ActiveState -p NRestarts -p StartLimitIntervalUSec
ActiveState=activating NRestarts=16 StartLimitIntervalUSec=0 # still retrying
The misplaced key leaves the default in effect: 5 starts within 10 seconds, then the unit goes to failed and stays there until someone runs systemctl reset-failed or reboots.
Why it matters in practice
The usual trigger is a network outage at boot. A service that needs the network fails 5 times in a row and is then permanently dead, even after the network comes back. With Restart=always in the file, everyone assumes it will recover.
Why the key is in [Unit], and the compat trap
Start rate limiting applies to every way a unit can be started: manual starts, dependencies, timers and sockets, not only service restarts. So the current settings, StartLimitIntervalSec= and StartLimitBurst=, are generic unit settings that belong in [Unit].
The trap comes from backward compatibility. Older systemd put the limit in [Service] under the name StartLimitInterval= (no Sec). systemd 255 (Ubuntu 24.04) still honors that legacy spelling in [Service], with no warning:
[Service]
StartLimitInterval=0 # legacy name, legacy place → works (StartLimitIntervalUSec=0)
StartLimitIntervalSec=0 # new name, legacy place → "Unknown key", ignored
So an old snippet works, but "modernizing" it by adding Sec without moving the line quietly breaks it. That's the version this server had.
Catch it: systemd-analyze verify
$ sudo systemd-analyze verify /etc/systemd/system/sl-wrong.service
/etc/systemd/system/sl-wrong.service:7: Unknown key name 'StartLimitIntervalSec' in section 'Service', ignoring.
Run it on every unit you write or generate. This server's agent now does that before installing any unit file. To check the value that's actually in effect on a running service:
systemctl show <unit> -p StartLimitIntervalUSec -p StartLimitBurst
The fix
Move the line into [Unit], then daemon-reload. You don't need to restart the service; the new limit applies from then on:
[Unit]
Description=...
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
ExecStart=...
Restart=always
RestartSec=10
If "retry forever" is too blunt, keep a limit but set it on purpose. For example, StartLimitIntervalSec=300 with StartLimitBurst=10, plus an OnFailure= unit that alerts you.
Need a VPS to try this on? Everything here was tested on a DigitalOcean Ubuntu 24.04 droplet: get one on DigitalOcean. Referral link: if you sign up through it and spend $25, the site owner gets $25 in DigitalOcean credit. Your price is the same.