What a systemd cyclic dependency error means
During boot, systemd builds a dependency graph between units (services, targets, sockets, etc.). A cyclic dependency occurs when two or more units reference each other as required (via Requires, Wants, PartOf, or After combined with other directives), forming a closed loop. systemd cannot determine the startup order for such units and aborts the process, displaying an error.
Typical symptoms:
- Messages appear in logs (
journalctl -xeorsystemctl status <unit>):Dependency cycle detected: foo.service → bar.service → foo.service. - Services involved in the cycle transition to
failedordeadstate. - The system may hang during the boot phase (e.g., at
Starting...). - The
systemctl list-dependenciescommand for the problematic unit fails or shows a recurring chain.
This error is critical: it prevents at least one service from starting, and in the worst case, halts the entire system boot.
Common causes
- Misconfigured dependency directives in unit files. For example,
serviceA.servicehasRequires=serviceB.service, whileserviceB.servicehasRequires=serviceA.service. - Dependency chains through target units. For instance,
multi-user.targetdepends onnetwork.target, which depends on a service that requiresmulti-user.target. - Conflicting directives. Combining
Requires/WantswithConflictsorBefore/Aftercan create an implicit cycle. - Package errors. When installing third-party software, its unit files may contain cycles, especially if the package incorrectly declares dependencies.
- Manual editing without verification. An administrator might have added a dependency without accounting for existing connections.
Resolution methods
Method 1: Manual analysis and editing of unit files
This method is suitable when you know the approximate names of the problematic units.
- Identify the units involved in the cycle. Use:
systemd-analyze critical-chain
This command shows the boot chain and indicates where a delay or cycle occurs. Look for repeating unit names.
Or for a specific unit:systemctl list-dependencies <unit_name> --all
If a cycle exists, the output will be interrupted or show the same units multiple times. - Visualize the dependency graph (optional but helpful). Install
graphviz:sudo apt install graphviz # Debian/Ubuntu sudo yum install graphviz # CentOS/RHEL
Then generate an SVG file:systemd-analyze plot > dependencies.svg
Opendependencies.svgin a browser and look for a cycle (a closed loop of arrows). - Locate the unit files. For each unit in the cycle, determine its source:
systemctl status <unit_name> | grep Loaded
The output shows the path:/etc/systemd/system/(user overrides) or/lib/systemd/system/(from a package). - Edit the unit files. Open each file in an editor (e.g.,
sudo nano /path/to/unit.service). Find directives likeRequires=,Wants=,After=,Before=. Remove or modify the reference that closes the cycle. For example, ifserviceArequiresserviceBandserviceBrequiresserviceA, remove one dependency (often you can keepWants=instead ofRequires=or removeAfter=). - Reload the systemd configuration:
sudo systemctl daemon-reload - Verify the result:
systemctl status <unit_name> systemd-analyze critical-chain
The error should disappear.
Method 2: Using systemd-analyze verify for automatic checking
systemd-analyze verify checks the syntax and logic of unit files, including cycles.
- Run verification for all units:
sudo systemd-analyze verify --fail --no-pager
The--failflag makes the command exit with a non-zero code on errors, and--no-pagerdisables paged output. The output will list files and lines with issues, including cyclic dependencies. - If the output is too long, check individual units:
sudo systemd-analyze verify /etc/systemd/system/foo.service - Fix the indicated files as in Method 1.
- Reload the daemon and verify.
Method 3: Temporarily disabling problematic units (mask)
If the cycle prevents system boot (e.g., you cannot access a shell), boot into recovery mode or use a live-USB.
- Identify the cycle via
systemd-analyzefrom recovery mode, or if the system partially boots, checkjournalctl -b -1(logs from the previous boot). - Temporarily mask one unit in the cycle:
sudo systemctl mask <unit_name>
This creates a symlink to/dev/null, preventing the unit from starting. - Reboot the system. It should boot without the error (though functionality related to the masked unit will be unavailable).
- After booting, fix the unit files (Method 1), then unmask:
sudo systemctl unmask <unit_name> sudo systemctl daemon-reload sudo systemctl restart <unit_name>
Method 4: Updating or reinstalling the package
If the cycle is caused by a package from a repository (e.g., after an update):
- Find the package owning the unit:
dpkg -S /lib/systemd/system/foo.service # Debian/Ubuntu rpm -qf /usr/lib/systemd/system/foo.service # CentOS/RHEL - Update the package to the latest version—the issue may have been fixed in a newer release:
sudo apt update && sudo apt upgrade <package_name> # Debian/Ubuntu sudo yum update <package_name> # CentOS/RHEL - If updating doesn't help, reinstall the package:
sudo apt install --reinstall <package_name> # Debian/Ubuntu sudo yum reinstall <package_name> # CentOS/RHEL
Reinstalling replaces unit files with defaults, potentially removing the cycle. - Reload systemd and verify.
Method 5: Using systemd-analyze dump for deep analysis
If previous methods fail, obtain a full dump of systemd's state:
- Create a dump:
sudo systemd-analyze dump > systemd-dump.txt - Manually search for cycles. Open the file and find all occurrences of
Requires=,Wants=,After=for suspect units. Map the chain on paper or in a graphics editor. - Pay special attention to "want" and "require" chains. Cycles often form via
WantedBy=in[Install]sections. For example,serviceAhasWantedBy=multi-user.target, andserviceB(which depends onserviceA) also hasWantedBy=multi-user.targetandRequires=serviceA. This isn't always a cycle, but ifserviceAalso requiresserviceB, a cycle will occur. - Fix the files and reload the daemon.
Prevention
- Test unit files before installation. Use
systemd-analyze verify <file>. - Avoid mutual
Requires=. If service A needs service B,Requires=Bin A is sufficient. Do not add a reverse dependency in B unless absolutely necessary. - Use
Wants=instead ofRequires=if the dependency is not critical. This reduces cycle risk. - Group services via targets. Create a target unit (e.g.,
myapp.target) and add services to it viaWantedBy=. Then enable only the target. - Regularly check dependencies after changes:
systemctl list-dependencies <key_unit>. - When updating packages, review changelogs for dependency changes.
- Keep systemd updated. Newer versions have improved dependency handling and warnings.
This article should help you quickly diagnose and resolve cyclic dependencies in systemd, restoring service and system operation.