The ExecStart directive in your systemd unit file is failing because the path to the executable it’s trying to run is incorrect, leading the system to believe the command simply doesn’t exist.

This is a common issue when dealing with custom services or when system updates might have shifted executable locations. The core problem is that systemd, when instructed to start a service via ExecStart=/path/to/executable, performs a lookup for /path/to/executable. If it doesn’t find a file at that exact path, or if the file isn’t executable by the user systemd is running as, it bails out with a "not found" error, even if the executable is present elsewhere or has permission issues.

Here’s a rundown of the most frequent culprits and how to fix them:

1. Typo in the ExecStart Path: This is the most straightforward, yet surprisingly common, error. A single misplaced character, a missing slash, or an incorrect directory name will cause the lookup to fail.

  • Diagnosis: Manually attempt to execute the command as specified in your ExecStart line. For example, if your unit file has ExecStart=/usr/local/bin/my-app, try running sudo -u <user_running_service> /usr/local/bin/my-app (replace <user_running_service> with the user specified in User= or systemd’s default if none is set). Also, run ls -l /usr/local/bin/my-app to verify its existence.
  • Fix: Carefully re-examine your unit file and compare the ExecStart path character by character with the actual location of your executable. Correct any discrepancies. For instance, change ExecStart=/usr/local/bin/my-app to ExecStart=/usr/local/bin/my-app if you found a typo.
  • Why it works: Ensures systemd is pointing to the exact, correct file.

2. Executable Not in Systemd’s PATH (and not an absolute path): If your ExecStart directive uses a command name without a leading slash (e.g., ExecStart=my-app), systemd will try to find my-app in its PATH environment variable. This PATH is often minimal for security reasons, especially for services.

  • Diagnosis: Check the PATH environment variable that systemd is using. You can get a sense of this by creating a temporary unit file that just prints the PATH:
    [Unit]
    Description=Print PATH
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c 'echo $PATH'
    
    [Install]
    WantedBy=multi-user.target
    
    Then sudo systemctl daemon-reload, sudo systemctl start print-path.service, and sudo journalctl -u print-path.service. Compare this PATH to where your executable is located.
  • Fix: Always use the absolute path to your executable in ExecStart. For example, if my-app is located at /opt/my-app/bin/my-app, change your directive to ExecStart=/opt/my-app/bin/my-app.
  • Why it works: Explicitly telling systemd the full path bypasses the need for it to search through its limited PATH environment.

3. Permissions Issues: The executable file might exist, but the user systemd is trying to run the service as doesn’t have execute permissions for it.

  • Diagnosis: First, identify the user the service runs as. Check the User= directive in your unit file. If it’s not set, systemd defaults to root. Then, check the permissions of the executable: ls -l /path/to/your/executable.
  • Fix: Grant execute permissions to the appropriate user or group. If the service runs as myuser and the executable is /opt/my-app/bin/my-app and owned by root:root, you might use: sudo chown myuser:myuser /opt/my-app/bin/my-app or sudo chmod u+x /opt/my-app/bin/my-app if myuser is the owner, or sudo chmod +x /opt/my-app/bin/my-app if execute permission for 'others' is sufficient (be cautious with this). A common scenario is making it executable for the group the user belongs to.
  • Why it works: Ensures the user specified in the unit file has the necessary rights to execute the program.

4. Executable Moved or Deleted by a Package Manager/Update: System updates can sometimes relocate executables or remove them if a package is upgraded or replaced.

  • Diagnosis: Use find to locate the executable across your filesystem. For example: sudo find / -name my-app -type f 2>/dev/null. This will search for files named my-app starting from the root directory.
  • Fix: Once located, update your ExecStart directive with the new, correct path found by find. If the executable was removed and replaced by a newer version in a different location, update your ExecStart accordingly.
  • Why it works: Points systemd to the executable’s current, valid location.

5. Incorrectly Specified Interpreter (for scripts): If ExecStart points to a script (e.g., a Python or Bash script), and the shebang line (#!/usr/bin/env python3 or #!/bin/bash) is incorrect or the interpreter itself isn’t found, systemd might report the script as "not found" because it can’t execute it.

  • Diagnosis: Check the shebang line at the very top of your script. Verify that the interpreter specified (e.g., /usr/bin/python3) actually exists and is executable. Try running the script directly from the command line: /path/to/your/script.sh.
  • Fix: Correct the shebang line to point to the correct interpreter path. If #!/usr/bin/python3 fails, but #!/usr/bin/env python3 works, use that. Ensure the interpreter binary itself is correctly installed and accessible.
  • Why it works: Systemd, or the shell it invokes, needs to find the interpreter to run the script.

6. Incorrect Working Directory (WorkingDirectory=): While not directly causing an "ExecStart not found" error, an incorrect WorkingDirectory= combined with a relative path in ExecStart could lead to this if the script/program expects to be run from a specific directory and uses relative paths internally for its own dependencies or executables. However, the primary "not found" error usually stems from the ExecStart path itself.

  • Diagnosis: Review your WorkingDirectory= directive. Ensure it’s set to a valid, existing directory.
  • Fix: Correct the WorkingDirectory= path to the intended directory.
  • Why it works: Ensures the service starts in the expected environment, allowing it to find its own resources if it relies on relative paths.

After fixing your unit file, remember to always run sudo systemctl daemon-reload to make systemd re-read the configuration files, and then sudo systemctl restart your-service-name.service to apply the changes.

The next error you’ll likely encounter if this was the only issue is a "permission denied" error from the executed program, or a specific error message from the application itself indicating missing configuration files or dependencies.

Want structured learning?

Take the full Systemd course →