Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
FREEDOM251

Freedom251 › Blog › ExecStart

Fix the systemd “Executable Path Is Not Absolute” Error

By Freedom251 Team · · 13 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The warning means systemd cannot use the first token in ExecStart= as a valid executable. Put a real executable at the beginning of the command—preferably its absolute path—then reload the manager and restart the unit. For a script, call an interpreter such as /bin/bash explicitly or use an executable script with a valid shebang. Variables, shell built-ins, and shell-style command strings are not dependable substitutes for that first token.

What the warning actually means

ExecStart= is parsed by systemd, not by an interactive shell. The parser must identify the program that the service manager will start before it can process the remaining arguments. In the versions and situations that produce this warning, the first token is not accepted as an executable path, so systemd ignores the command. A unit can then appear loaded while having no usable start command.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most portable form is an absolute path such as /usr/local/bin/myapp. An absolute path starts at the root directory and does not depend on the service manager guessing which directory contains the program. A quoted command that contains spaces can still fail during this initial check. Upstream issue #2132 records the exact message for such a case: Executable path is not absolute, ignoring: '/tmp/space bin'. The result is the same practical problem: no valid executable is available for ExecStart=.

A variable in the executable position has a similar risk. Upstream issue #1274 shows $CELERY_BIN as the first token and reports the same warning. Systemd does not turn that token into a shell-expanded command in the way an interactive shell would. Resolve the variable yourself and write the resulting path, or invoke a shell deliberately when shell expansion is genuinely required.

Repair the unit in the right order

Use this sequence so that you fix the unit systemd actually loads, not an unused copy elsewhere on the machine.

  1. Inspect the main unit and drop-ins. Run systemctl cat example.service. This prints the vendor unit followed by any administrator drop-ins, making overrides visible. Then run systemctl show example.service -p FragmentPath -p DropInPaths to see the main file location and every drop-in directory.
  2. Find the executable installed on this host. For a program found through your shell, run command -v myapp. Confirm the candidate directly with a command such as ls -l /usr/local/bin/myapp. Do not copy a path from a different machine or from a shell session running under another user.
  3. Make the executable the first token. Edit the appropriate unit or create a drop-in and use a form like:
[Service]
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
  1. Choose the correct script form. Either name an interpreter explicitly, for example ExecStart=/bin/bash /opt/myapp/start.sh, or make the script executable, give it a valid shebang, and call it by its own absolute path:
[Service]
ExecStart=/opt/myapp/start.sh
  1. Remove shell syntax from the executable position. Do not put exec, source, export, a pipe, command substitution, or a variable reference before the program path. If shell grammar is essential, start a shell by its absolute path and pass the command to -c; treat that as a different process model with different quoting and signal behavior.
  2. Reload and exercise the changed unit. Run systemctl daemon-reload, then systemctl restart example.service. Inspect both systemctl status example.service --no-pager and journalctl -u example.service -b --no-pager.

If the warning disappears but the service still exits, you have moved past parsing. Continue with the execution checks later in this guide rather than changing ExecStart= randomly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inspect which file systemd is really using

Editing the wrong file is a common reason an apparently correct repair has no effect. Package updates commonly install a unit under /usr/lib/systemd/system/ or /lib/systemd/system/, while local changes are normally placed in a drop-in under /etc/systemd/system/example.service.d/. The exact vendor directory varies by distribution, which is why the manager’s own output is authoritative.

Read the merged definition

systemctl cat example.service shows the effective text in order. Look for multiple ExecStart= lines, an old command in a drop-in, or an empty assignment intended to clear a vendor command. A service that permits only one start command may need the previous value cleared before a replacement is added:

[Service]
ExecStart=
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml

Use that clearing form only when the unit’s service type and existing definition require it. Preserve other settings such as User=, WorkingDirectory=, restart policy, and sandbox restrictions unless you have a separate reason to change them.

Confirm the loaded paths

systemctl show example.service -p FragmentPath -p DropInPaths identifies the main fragment and drop-ins that the manager loaded. If your editor changed a different copy, move the edit to the listed location or create a drop-in in the displayed drop-in directory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why an absolute executable path is the safest choice

Systemd’s documentation has changed over time. Older text required an absolute path for the executable. Later behavior permits a simple file name without slashes and resolves it through a fixed search path. That compatibility difference is why an explicit path remains the clearest choice even on a current distribution.

Form Portability across systemd versions Path dependence Maintenance trade-off
/usr/local/bin/myapp Works with old and new interpretations of ExecStart=. Does not depend on the manager’s search path. Must be updated if the software is deliberately moved; a stable symlink can provide an upgrade point.
myapp Accepted only where the installed systemd version supports a simple filename. Resolved through the service manager’s fixed search path, not your interactive shell’s PATH. Convenient when packaging keeps a stable name, but behavior can differ between hosts.

The system manager documents a fixed path of /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin. A user’s shell may add directories such as a language-runtime or home-bin directory, and those additions are not automatically inherited by a system service. If a program is installed outside the manager’s path, use its absolute location instead of assuming that command -v from your login shell proves the service can find it.

Scripts: direct execution or an explicit interpreter?

A script is not itself an executable binary unless the operating system can use its shebang and the file has execute permission. Select the form that matches how the script is maintained.

Configuration What must be true Interpreter selection Operational implications
ExecStart=/opt/myapp/start.sh The file is executable and begins with a valid shebang, such as #!/bin/bash. The target interpreter must exist at the shebang path. Chosen by the shebang in the script. The script is the direct service process, so stop signals and exit status are normally delivered to it.
ExecStart=/bin/bash /opt/myapp/start.sh The script only needs to be readable by the service user; it does not need its execute bit for this invocation. The path to Bash must exist. Forced to the explicitly named Bash interpreter, regardless of a different shebang. Bash is the direct process started by systemd and interprets the file as an argument.

When direct execution is appropriate

Use the direct form when the script’s shebang is intentional and stable. Check it with head -n 1 /opt/myapp/start.sh, then check permissions with ls -l /opt/myapp/start.sh. A missing shebang can lead to an interpreter error even after the executable-path warning is fixed. A relative interpreter name in the shebang can also fail if that interpreter is not resolvable in the service environment; an absolute interpreter path is more predictable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When to name Bash explicitly

Use /bin/bash script when the file is a Bash script that is intentionally kept non-executable, when you need to override an unsuitable shebang, or when deployment permissions cannot set the execute bit. This does not make POSIX shell syntax, Python, or another language valid: choose the interpreter that matches the file. A Python script, for example, needs the absolute path to the intended Python interpreter or an executable shebang that names it.

Handling spaces in executable and script paths

Systemd has its own command-line parsing and escaping rules. A unit file is not a shell script, so copying a command that worked after shell quoting can create a different token. The reported failure for /tmp/space bin demonstrates the danger of putting a quoted, space-containing path directly in the executable position.

The most robust design is to install the service executable and its scripts under paths without spaces. If that is impossible, keep an unambiguous executable first and pass the space-containing path as an argument using systemd’s quoting or escaping syntax, then verify the merged unit. For example, an interpreter can remain the first token while the script path is a later argument:

[Service]
ExecStart=/bin/bash "/opt/my app/start.sh"

Here the quotes delimit one systemd argument; they are not an invitation to place an entire shell command inside ExecStart=. Test the exact unit after editing because escaping, embedded quotes, backslashes, and trailing arguments can change token boundaries. If an application itself accepts a path with spaces, keep that path in the argument position rather than trying to make it the parser’s command string.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Variables, exec, and other shell features

Systemd does support environment assignments and substitutions in specific contexts, but the first word still has to identify the program systemd will launch. A line such as ExecStart=$CELERY_BIN worker asks the parser to treat the literal variable reference as the executable token; it is not equivalent to an interactive shell expanding the variable first.

Likewise, exec is a shell built-in. It replaces a shell process with another program when interpreted by a shell, but systemd cannot use it as the executable unless you explicitly start that shell. The same applies to source, export, pipes, redirections, ;, &&, command substitution, and wildcard expansion.

If shell syntax is truly required

Invoke the shell by absolute path and pass -c plus the command string:

[Service]
ExecStart=/bin/bash -c 'exec /usr/local/bin/myapp --config /etc/myapp/config.yml'

This pattern makes /bin/bash the executable token and lets Bash interpret the following string. It also introduces another quoting layer: systemd first parses the unit line, then Bash parses the command string. Recheck every quote, backslash, variable, and redirection. Signal delivery and process accounting can differ from direct execution, especially if the shell starts pipelines or fails to replace itself with the long-running program. Prefer a small, separately tested wrapper script when the command needs substantial shell logic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reload, restart, and verify the result

Changing a unit file does not automatically replace the manager’s in-memory definition. Always reload before testing:

systemctl daemon-reload
systemctl restart example.service
systemctl status example.service --no-pager
journalctl -u example.service -b --no-pager

systemctl status gives the current state and recent messages. The journal shows the complete boot’s messages for that unit and often identifies a missing interpreter, permission denial, or configuration error that is unrelated to the original parser warning. If you changed only a drop-in, systemctl cat after the reload is a quick confirmation that the new command is merged.

If parsing succeeds but the service still fails

Once systemd accepts the first token, investigate the program as a normal service process. The original warning cannot reveal host-specific conditions such as a missing file, an inaccessible working directory, or a sandbox rule.

Confirm the target and its permissions

  • Run ls -l /usr/local/bin/myapp or the equivalent for the script. The path must exist in the service’s filesystem view, and the service account must be able to traverse its parent directories.
  • For direct scripts, verify the execute bit and the first-line shebang. For interpreter form, verify that the named interpreter exists and can read the script.
  • Check whether the executable is a symlink. Follow it to a real target that remains present after package upgrades or deployment cleanup.

Check the service identity and files it needs

A command that works as root or as your login user may fail under the unit’s User= and Group=. Confirm that this account can read the configuration file, write required state or log directories, and access certificates, sockets, and data files. A relative path in the application may resolve from the unit’s WorkingDirectory=, not from your home directory. Set an explicit working directory when the application requires one and ensure that directory exists.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Separate application errors from launch errors

An exit code after a successful start, a configuration parse error, or a port-binding failure is an application-level problem. Use the journal output to identify it instead of changing the executable path. If the service is repeatedly restarted, temporarily inspect its restart policy and the first failure message; an automatic restart can otherwise hide the original cause among later attempts.

Account for sandboxing

Settings that restrict paths, system calls, devices, networking, or writable locations can block a perfectly valid executable. Review the unit’s security and namespace directives when the journal reports permission or “file not found” errors despite the file existing on the host. The relevant question is whether the file is visible and permitted inside the service’s execution context.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Version differences and ExecSearchPath=

The accepted form of an executable name depends partly on the systemd version. Documentation history distinguishes the older absolute-path requirement from later behavior that permits a simple file name without slashes and resolves it through a fixed search path. Do not infer a host’s behavior from a different distribution’s manual.

ExecSearchPath= is documented as a colon-separated list of absolute directories used to locate executables and was added in systemd version 250. Its presence, default behavior, and interaction with other settings are therefore version-sensitive. If you rely on a non-absolute command name, confirm that the running manager supports the directive and that the required directory is in the effective search list. An explicit absolute path avoids that dependency.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Situation Safer decision Reason
Units must run on mixed or older distributions. Use a fully qualified executable path. It does not rely on newer filename-resolution behavior.
A current systemd installation deliberately standardizes executable directories. A simple filename may be acceptable after checking the manager’s documented search path. The manager, not the login shell, resolves the name.
The executable is installed in a private directory. Use its absolute path or explicitly configure a supported search path. The documented fixed path does not include arbitrary application directories.

Common symptoms and targeted fixes

“Executable path is not absolute” appears immediately after editing

Inspect the first token character by character. Replace a variable, shell built-in, command name that is unsupported on that systemd version, or quoted shell command with an actual executable path. Then reload the manager; merely saving the file leaves the old definition loaded.

The warning names a path with spaces

Do not quote an entire shell command and expect systemd to execute it. Put a real interpreter or executable first, and pass the space-containing script or data path as a later argument using systemd’s own escaping. If possible, move the service to a path without spaces.

The unit loads but says there is no start command

Check every drop-in with systemctl cat. A malformed override may have replaced the vendor command, or an empty ExecStart= may have cleared it without adding a valid replacement. Correct the merged definition, run daemon-reload, and inspect it again.

The path is absolute, but the service exits with “permission denied”

The parser has already accepted the command. Check execute permissions, directory traversal, the service account, mount options, and sandbox restrictions. For a script, check both its execute bit and its shebang, or invoke the intended interpreter explicitly.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The command works in a terminal but not as a service

Compare environments rather than adding shell syntax. The manager’s fixed search path differs from an interactive shell’s PATH; the service may also have a different user, working directory, environment, and filesystem view. Convert every required program reference to an absolute path and grant the service account access to its files.

The service starts and then stops unexpectedly

Read the unit journal for the first exit. A valid ExecStart= only proves that systemd could launch the process; it does not prove that the application accepted its options, found its configuration, or stayed in the foreground. Resolve that separate application or process-supervision issue in the unit’s documented settings.

Keeping the fix maintainable

Prefer a stable installation path for the service entry point. If releases live in versioned directories, a deliberately managed symlink such as /usr/local/bin/myapp can let deployments change the target without rewriting the unit. Verify the symlink target after upgrades and remove obsolete releases only after the service has been tested.

Keep complex shell logic in a version-controlled wrapper script with its own interpreter, permissions, and tests. The unit then has a simple, inspectable ExecStart=/absolute/path/to/wrapper, while the script handles argument validation and setup. This reduces nested quoting and makes failures visible in the journal.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

After every deployment that changes a unit or drop-in, use the same four-part check: inspect the merged text, reload the manager, restart the service, and read both status and journal output. That routine catches stale manager state as well as genuine execution failures.

Bottom line

Fix the warning at the command boundary: make the first ExecStart= token a real executable, preferably an absolute path. Treat scripts, variables, spaces, and shell operators as separate concerns, choose an explicit interpreter when needed, then reload and verify the unit. If the parser accepts the command but startup still fails, diagnose permissions, interpreters, configuration, working directory, user, and sandbox settings instead of continuing to alter the path.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

ExecStartLinuxservice troubleshootingsystem administrationsystemd

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.