Unstable or failing systemd services on Linux often come from missing dependency units or runtime settings that point to the wrong executable, user, or file path. A fast dependency and path review usually surfaces the real cause sooner than repeated restarts and reduces the risk of hitting start-limit lockouts.

systemd builds the final service definition from the unit file plus any drop-in overrides under /etc/systemd/system/<unit>.d/, then computes the dependency graph from directives such as Requires, Wants, and ordering rules like After and Before. The same merged configuration also controls runtime behavior—ExecStart command paths, optional EnvironmentFile entries, the User and Group the process runs as, and any working or state directories the service expects.

Some dependencies are implicit (for example mount units derived from path usage) and drop-ins can override earlier settings, so checking the effective configuration matters more than reading a single file. systemd does not execute ExecStart through a shell, so relative paths, shell built-ins, and interactive quoting assumptions can fail in a unit context. File and directory checks may require sudo privileges, and remote systems benefit from having console access available before applying changes that affect service startup.

Steps to check Linux service dependencies and runtime paths with systemctl:

  1. Display the effective unit file and any drop-in overrides.
    $ systemctl --no-pager cat example.service
    # /etc/systemd/system/example.service
    [Unit]
    Description=Example API
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    Type=simple
    User=svcuser
    Group=svcuser
    EnvironmentFile=-/etc/default/example
    ExecStart=/usr/local/bin/example-api --config /etc/example/example.conf
    WorkingDirectory=/var/lib/example
    Restart=on-failure
    RestartSec=1s
    
    [Install]
    WantedBy=multi-user.target

    Replace service-name.service with the actual unit name, including suffixes like .service, .socket, or .timer.

  2. Extract dependency directives from the effective unit file.
    $ systemctl --no-pager cat example.service | grep -E '^(Requires|Wants|BindsTo|Requisite|PartOf|After|Before)='
    Wants=network-online.target
    After=network-online.target
  3. List the resolved dependency tree for the unit.
    $ systemctl --no-pager list-dependencies --after --all --plain --full example.service | head -n 12
    example.service
      -.mount
      -.slice
      blockdev@dev-disk-by\x2duuid-c7f70fb1\x2dad04\x2d47c0\x2d8aa2\x2d873cbef19d05.target
      system.slice
      systemd-journald.socket
      basic.target
      systemd-ask-password-plymouth.path
      plymouth-start.service
      keyboard-setup.service
      systemd-udev-trigger.service
      systemd-udevd-control.socket

    Use --before to view reverse ordering, and --reverse to list units that pull the service in.

  4. Extract runtime path directives and service identity settings from the effective unit file.
    $ systemctl --no-pager cat example.service | grep -E '^(ExecStart|ExecStartPre|ExecStartPost|WorkingDirectory|EnvironmentFile|User|Group|RuntimeDirectory|StateDirectory|CacheDirectory|LogsDirectory|ConfigurationDirectory|PIDFile)='
    User=svcuser
    Group=svcuser
    EnvironmentFile=-/etc/default/example
    ExecStart=/usr/local/bin/example-api --config /etc/example/example.conf
    WorkingDirectory=/var/lib/example

    A leading - in EnvironmentFile makes the file optional, while ExecStart must reference an absolute executable path because systemd does not invoke a shell.

  5. Verify that referenced executables and files exist and have expected permissions.
    $ sudo ls -l /usr/local/bin/example-api /etc/example/example.conf /etc/default/example
    -rw-r--r-- 1 root root  23 Jan 10 06:59 /etc/default/example
    -rw-r--r-- 1 root root  27 Jan 10 06:59 /etc/example/example.conf
    -rwxr-xr-x 1 root root 607 Jan 10 07:00 /usr/local/bin/example-api

    A missing ExecStart binary or an unreadable non-optional EnvironmentFile causes immediate start failure and may trigger systemd start-limit suppression (restarts blocked until the limit window resets).

  6. Check that referenced working or state directories exist and are owned appropriately for the configured service account.
    $ sudo ls -ld /var/lib/example /var/log/example /run/example
    drwxr-xr-x 2 svcuser svcuser   40 Jan 10 07:08 /run/example
    drwxr-x--- 2 svcuser svcuser 4096 Jan 10 06:59 /var/lib/example
    drwxr-xr-x 2 svcuser svcuser 4096 Jan 10 06:59 /var/log/example

    Paths under /run/ are often created at service start and may not exist while stopped unless RuntimeDirectory (or similar) is configured.

  7. Confirm that prerequisite units from the dependency chain are active.
    $ systemctl is-active network-online.target systemd-journald.socket
    active
    active

    List globally failed units when a prerequisite is suspected:

    $ systemctl --no-pager --failed