Skip to content

Fix systemd "Start request repeated too quickly" (start-limit-hit)

systemdtroubleshootingservicesrestartlinux
6 min read

Quick Answer

Start request repeated too quickly means the service crashed and was restarted more than StartLimitBurst times (default 5) within StartLimitIntervalSec (default 10s), so systemd stopped trying and marked it failed with Result: start-limit-hit. The limit is never the cause. The program failed at least five times first, and its own error is in the journal: journalctl -u UNIT -n 50. After a fast crash loop, systemctl status may show only systemd's limit messages. Until you clear the counter with systemctl reset-failed UNIT, systemd refuses every start, including manual ones, with Job for UNIT failed because start of the service was attempted too often. With Restart=on-failure and the default RestartSec=100ms, a program that dies at once uses all five starts in about half a second. Fix the program's error first, then set RestartSec= so five restarts span more than the interval. The start limit then stops only real tight loops.

Decode the whole systemctl status output

The systemctl status Explainer reads pasted systemctl status or journalctl -u output and names the cause, including start-limit-hit, crash loops, timeouts and OOM kills. Nothing is uploaded.

The service crashed, systemd restarted it four times in half a second, and now systemctl start refuses outright. The usual fix on forums is to raise StartLimitBurst, which makes the same crash loop run longer before it stops. The limit did its job. What it hid is the error the program printed five times before it tripped.

What Does start-limit-hit Look Like?

Reproduced on 2026-10-10 on this machine (Kali, systemd 261) with a throwaway user unit: ExecStart= prints cannot bind 127.0.0.1:8099: address in use to stderr and exits 1, with Restart=on-failure and nothing else set. The first systemctl --user start returned 0. Three seconds later:

text
$ systemctl --user status bsdemo-loop.service × bsdemo-loop.service - bashsnippets demo crashloop Loaded: loaded (~/.config/systemd/user/bsdemo-loop.service; static) Active: failed (Result: start-limit-hit) since Sat 2026-10-10 18:47:18 CDT; 1s ago Duration: 35ms Invocation: 8894923e7a6948b78219ca5b17803fb1 Process: 88911 ExecStart=/bin/bash -c echo cannot bind 127.0.0.1:8099: address in use >&2; exit 1 (code=exited, status=1/FAILURE) Main PID: 88911 (code=exited, status=1/FAILURE) Mem peak: 2M CPU: 6ms Oct 10 18:47:18 laptop systemd[1154]: bsdemo-loop.service: Scheduled restart job, restart counter is at 5. Oct 10 18:47:18 laptop systemd[1154]: bsdemo-loop.service: Start request repeated too quickly. Oct 10 18:47:18 laptop systemd[1154]: bsdemo-loop.service: Failed with result 'start-limit-hit'. Oct 10 18:47:18 laptop systemd[1154]: Failed to start bsdemo-loop.service - bashsnippets demo crashloop.

Every log line in that view is systemd's. The program's cannot bind message, the actual problem, is not on screen. And the service is now parked:

text
$ systemctl --user start bsdemo-loop.service Job for bsdemo-loop.service failed because start of the service was attempted too often. See "systemctl --user status bsdemo-loop.service" and "journalctl --user -xeu bsdemo-loop.service" for details. To force a start use "systemctl --user reset-failed bsdemo-loop.service" followed by "systemctl --user start bsdemo-loop.service" again. exit=1

Why Did It Trip So Fast?

The defaults, read from the unit with systemctl show, are StartLimitBurst=5, StartLimitIntervalSec=10s and RestartSec=100ms. Every automatic restart counts as a start. A program that dies immediately therefore restarts every ~100 ms and spends its five starts in about half a second, well inside the 10-second window. Any service with Restart= and a startup bug will hit the limit this way, and that is intended: without it, the loop would never stop.

How Do I Fix It?

  1. Read the program's error. journalctl -u UNIT -n 50 (with --user for a user unit) goes back past systemd's lines. Here it was the port. Fix that first; nothing else on this page matters until the program can start.
  2. Clear the counter. systemctl reset-failed UNIT && systemctl start UNIT. The counter does not reset when you edit the unit or run daemon-reload.
  3. Space the restarts in [Service], so that a transient failure (a database that is not up yet) gets retried over a meaningful window:
ini
[Unit] StartLimitIntervalSec=10s StartLimitBurst=5 [Service] Restart=on-failure RestartSec=3s

With those values, five restarts take 15 seconds, longer than the 10-second window, so the limit never trips on a slow crash. A service that keeps failing is retried every 3 seconds instead of being parked, so watch it with monitoring rather than relying on failed. StartLimit* belongs in [Unit] per systemd.unit(5). systemd 261 here still accepted the older StartLimitInterval= in [Service], but do not rely on it.

The same unit after that change, three seconds after starting:

text
$ ./start-limit-check.sh --user bsdemo-loop.service bsdemo-loop.service: Result=exit-code, Restart=on-failure, RestartSec=3s, restarts so far=0 start limit: 5 starts within 10s ✓ not rate-limited right now (Result=exit-code) exit=0 $ systemctl --user status bsdemo-loop.service --no-pager -n 0 | sed -n 3p Active: activating (auto-restart) (Result: exit-code) since Sat 2026-10-10 18:37:26 CDT; 1s ago

activating (auto-restart) means it is waiting out RestartSec before the next try. It is still broken, but it is no longer parked.

The Script

Save as start-limit-check.sh. It prints the limit math for a unit, says whether a crash loop can trip it, and when the unit is parked, prints the reset command and the last lines the program itself logged, with systemd's own lines filtered out.

bash
#!/bin/bash # Script: start-limit-check.sh # Purpose: "Start request repeated too quickly" hides the real crash behind systemd's rate limit, and raising the limit only hides it longer; this prints the limit math and the error that tripped it. # Usage: ./start-limit-check.sh [--user] UNIT set -euo pipefail CHECK="✓" CROSS="✗" SCOPE=() if [[ "${1:-}" == "--user" ]]; then SCOPE=(--user); shift; fi [[ $# -eq 1 ]] || { echo "usage: $0 [--user] UNIT" >&2; exit 2; } UNIT="$1" LOG_LINES=200 # how far back to look for the program's own output before the limit hit prop() { systemctl "${SCOPE[@]}" show -p "$1" --value "$UNIT"; } # show reports times like "10s" or "100ms"; convert to milliseconds so the two can be compared. to_ms() { local v=$1 total=0 n unit [[ "$v" == "infinity" || -z "$v" ]] && { echo 0; return; } while [[ "$v" =~ ^([0-9]+)(min|ms|us|h|s)(.*)$ ]]; do n=${BASH_REMATCH[1]} unit=${BASH_REMATCH[2]} v=${BASH_REMATCH[3]} case "$unit" in h) total=$((total + n * 3600000)) ;; min) total=$((total + n * 60000)) ;; s) total=$((total + n * 1000)) ;; ms) total=$((total + n)) ;; us) total=$((total + n / 1000)) ;; esac done echo "$total" } RESULT=$(prop Result) RESTART=$(prop Restart) BURST=$(prop StartLimitBurst) INTERVAL=$(prop StartLimitIntervalUSec) RESTART_SEC=$(prop RestartUSec) NRESTARTS=$(prop NRestarts) echo " $UNIT: Result=$RESULT, Restart=$RESTART, RestartSec=$RESTART_SEC, restarts so far=$NRESTARTS" echo " start limit: $BURST starts within $INTERVAL" INTERVAL_MS=$(to_ms "$INTERVAL") RESTART_MS=$(to_ms "$RESTART_SEC") # Every automatic restart counts as a start, so a program that dies at once spends the burst in burst*RestartSec. if [[ "$RESTART" != "no" ]] && (( INTERVAL_MS > 0 && BURST * RESTART_MS < INTERVAL_MS )); then echo "$CROSS a crash loop will trip the limit: $BURST restarts every ${RESTART_MS}ms take $((BURST * RESTART_MS))ms, inside the ${INTERVAL_MS}ms window" echo " RestartSec=$(( (INTERVAL_MS / BURST / 1000) + 1 ))s or more spreads them out; the limit then only stops a real tight loop" fi if [[ "$RESULT" == "start-limit-hit" ]]; then echo "$CROSS the unit is parked: systemd refuses every start, including yours, until you run:" echo " systemctl ${SCOPE[*]:+${SCOPE[*]} }reset-failed $UNIT && systemctl ${SCOPE[*]:+${SCOPE[*]} }start $UNIT" # The limit message is never the cause; the last line the program itself wrote usually is. CAUSE=$(journalctl "${SCOPE[@]}" -u "$UNIT" -n "$LOG_LINES" --no-pager -o short-iso 2>/dev/null | grep -v ' systemd\[[0-9]*\]: ' | grep -v '^-- ' | tail -3 || true) if [[ -n "$CAUSE" ]]; then echo " last lines from the program before the loop stopped:" while IFS= read -r line; do echo " $line"; done <<< "$CAUSE" else echo " the program logged nothing: the failure is in systemd's own lines (try journalctl ${SCOPE[*]} -u $UNIT -n 30)" fi exit 1 fi echo "$CHECK not rate-limited right now (Result=$RESULT)" exit 0

Prerequisites

bash 4 or later and systemd (systemctl show, journalctl). No root for user units. For system units, run it with sudo or as a user in the systemd-journal or adm group, or the journal lookup returns nothing.

How Does Each Check Work?

  • systemctl show reads the values systemd is using, including defaults that are not written in the unit file: Result, Restart, RestartUSec, StartLimitBurst, StartLimitIntervalUSec and NRestarts.
  • to_ms converts systemd's time strings (100ms, 10s, 1min 30s) to milliseconds so the two settings can be compared.
  • The loop test multiplies the burst by RestartSec. If that fits inside the interval, a program that dies at once will always trip the limit, and the script prints the RestartSec that would not.
  • The journal filter drops lines from systemd[PID] and keeps the rest, which are the lines the service's own processes wrote. Those are what to fix.

What Does the Script Print?

On the parked unit from the top of the page:

text
$ ./start-limit-check.sh --user bsdemo-loop.service bsdemo-loop.service: Result=start-limit-hit, Restart=on-failure, RestartSec=100ms, restarts so far=5 start limit: 5 starts within 10s ✗ a crash loop will trip the limit: 5 restarts every 100ms take 500ms, inside the 10000ms window RestartSec=3s or more spreads them out; the limit then only stops a real tight loop ✗ the unit is parked: systemd refuses every start, including yours, until you run: systemctl --user reset-failed bsdemo-loop.service && systemctl --user start bsdemo-loop.service last lines from the program before the loop stopped: 2026-10-10T18:47:17-05:00 laptop bash[88906]: cannot bind 127.0.0.1:8099: address in use 2026-10-10T18:47:17-05:00 laptop bash[88909]: cannot bind 127.0.0.1:8099: address in use 2026-10-10T18:47:18-05:00 laptop bash[88911]: cannot bind 127.0.0.1:8099: address in use exit=1

The cause is the last three lines. The port is taken, which Kill a Process on a Port and the Open Ports Explainer help track down.

What About a Watchdog That Resets It?

A cron watchdog that runs reset-failed and start every minute turns systemd's crash-loop protection off and replaces it with a slower crash loop. Auto-Restart a Linux Service covers the bounded version, which resets a few times and then alerts a human, alongside Restart= and health checks. If the service never starts at all, with status=203/EXEC, see Fix systemd status=203/EXEC.

Frequently Asked Questions

What does start request repeated too quickly mean?

systemd started the service, it exited, Restart= started it again, and that happened more than StartLimitBurst times (5 by default) inside StartLimitIntervalSec (10 seconds by default). systemd then gives up and marks the unit failed with Result: start-limit-hit. The message is a symptom: the real error is whatever made the program exit five times, which is in journalctl -u UNIT.

How do I reset start-limit-hit in systemd?

Run systemctl reset-failed UNIT, then systemctl start UNIT (add --user for a user unit, sudo for a system unit). Until reset-failed clears the counter, systemd refuses every start request for that unit, including ones you type by hand, with Job for UNIT failed because start of the service was attempted too often.

Where do StartLimitBurst and StartLimitIntervalSec go?

In the [Unit] section, which is where systemd.unit(5) documents them, for example StartLimitIntervalSec=60 and StartLimitBurst=5. Older guides put StartLimitInterval= in [Service]; systemd 261 on this machine still accepted that form, but [Unit] is the documented one. Run systemctl daemon-reload after the edit and check with systemctl show -p StartLimitBurst -p StartLimitIntervalUSec UNIT.

Should I set StartLimitBurst=0 or StartLimitIntervalSec=0?

Setting StartLimitIntervalSec=0 disables the limit, so a broken service restarts forever. Combined with the default RestartSec=100ms that is ten starts a second, each one logging an error. Prefer a RestartSec= long enough that the burst cannot fit in the interval: with the defaults, RestartSec=3s means five restarts take 15 seconds and never trip the 10-second window, while a genuinely tight loop still gets stopped.

Why does systemctl status not show the real error?

Its log section shows only the last few journal lines for the unit, and after a crash loop those are systemd's own Start request repeated too quickly and Failed with result lines. In the run on this page, none of the program's own error lines were in the status view. journalctl -u UNIT -n 50 goes back far enough, or start-limit-check.sh prints the program's last lines with systemd's filtered out.


Part of the bash snippets collection

Raw script, MIT licensed: scripts/start-request-repeated-too-quickly.sh on GitHub

PAID RESOURCE — $9

The Production Bash Toolkit

An operational script system + a 30-function shared library + a 52-page field guide. The production layer the free snippets don't cover.

Get the Toolkit →
curl -O bashlib-starter.sh

Get the bashlib starter

Ten functions I source into every script on my own boxes — strict-mode setup, an ERR trap that names the failing line, lock and timeout wrappers, and cleanup that runs on every exit path. One email, no sequence.

BashSnippets logo

Written by Travis

Creator of BashSnippets.xyz

bashsnippets.xyz/about

Related Snippets

Frequently Asked Questions

faq — snippet

What does start request repeated too quickly mean?

systemd started the service, it exited, Restart= started it again, and that happened more than StartLimitBurst times (5 by default) inside StartLimitIntervalSec (10 seconds by default). systemd then gives up and marks the unit failed with Result: start-limit-hit. The message is a symptom: the real error is whatever made the program exit five times, which is in journalctl -u UNIT.

faq — snippet

How do I reset start-limit-hit in systemd?

Run systemctl reset-failed UNIT, then systemctl start UNIT (add --user for a user unit, sudo for a system unit). Until reset-failed clears the counter, systemd refuses every start request for that unit, including ones you type by hand, with Job for UNIT failed because start of the service was attempted too often.

faq — snippet

Where do StartLimitBurst and StartLimitIntervalSec go?

In the [Unit] section, which is where systemd.unit(5) documents them, for example StartLimitIntervalSec=60 and StartLimitBurst=5. Older guides put StartLimitInterval= in [Service]; systemd 261 on this machine still accepted that form, but [Unit] is the documented one. Run systemctl daemon-reload after the edit and check with systemctl show -p StartLimitBurst -p StartLimitIntervalUSec UNIT.

faq — snippet

Should I set StartLimitBurst=0 or StartLimitIntervalSec=0?

Setting StartLimitIntervalSec=0 disables the limit, so a broken service restarts forever. Combined with the default RestartSec=100ms that is ten starts a second, each one logging an error. Prefer a RestartSec= long enough that the burst cannot fit in the interval: with the defaults, RestartSec=3s means five restarts take 15 seconds and never trip the 10-second window, while a genuinely tight loop still gets stopped.

faq — snippet

Why does systemctl status not show the real error?

Its log section shows only the last few journal lines for the unit, and after a crash loop those are systemd's own Start request repeated too quickly and Failed with result lines. In the run on this page, none of the program's own error lines were in the status view. journalctl -u UNIT -n 50 goes back far enough, or start-limit-check.sh prints the program's last lines with systemd's filtered out.