Exec format error
Linux service
troubleshooting
systemd
error handling

why am I getting Exec format error when I am writing my linux service?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

An Exec format error means Linux tried to execute a file whose format does not match what the kernel expects. In a service context, that usually means a bad shebang, wrong CPU architecture, Windows line endings, or an ExecStart target that is not actually executable. The fastest diagnosis is to inspect the target file directly instead of focusing only on the service unit.

Core Sections

What systemd Expects From ExecStart

ExecStart= must resolve to either:

  1. a native executable for the host architecture
  2. a script with a valid shebang
  3. an interpreter command followed by a script path

This works:

ini
1[Unit]
2Description=Demo service
3
4[Service]
5Type=simple
6ExecStart=/usr/local/bin/demo-service.sh
7Restart=on-failure
8
9[Install]
10WantedBy=multi-user.target

With a script:

bash
1#!/usr/bin/env bash
2set -euo pipefail
3
4echo "service started"
5sleep infinity

Without the shebang, Linux may try to execute raw text as if it were a binary and return ENOEXEC.

Common Causes of Exec format error

The most common root causes are:

  • missing or invalid shebang
  • Windows carriage-return line endings
  • binary compiled for the wrong architecture
  • 'ExecStart pointing to the wrong file'
  • shell-style command syntax assumed where systemd expects direct execution

Each one produces the same high-level failure but needs a different fix.

First Diagnostics to Run

Inspect both service logs and the target file:

bash
1systemctl status demo.service
2journalctl -u demo.service -n 50 --no-pager
3file /usr/local/bin/demo-service.sh
4head -n 1 /usr/local/bin/demo-service.sh
5ls -l /usr/local/bin/demo-service.sh

For binaries, compare architecture:

bash
uname -m
file /usr/local/bin/my-service

If uname -m says x86_64 and file reports an aarch64 binary, the error is explained immediately.

Fixing Script-Based Services

If the target is a script, use a correct shebang or call the interpreter explicitly.

Good options:

ini
ExecStart=/usr/local/bin/task-runner.py
ini
ExecStart=/usr/bin/python3 /usr/local/bin/task-runner.py

The explicit interpreter form is often clearer for services because it removes ambiguity.

Windows Line Endings Break Shebangs

If the script was edited on Windows, the shebang path can end with carriage return characters and become invalid. Convert line endings:

bash
sed -i 's/\r$//' /usr/local/bin/demo-service.sh

Then restart:

bash
sudo systemctl daemon-reload
sudo systemctl restart demo.service

This is one of the most common real-world causes when a script "looks fine" but still fails.

Fixing Binary-Based Services

For native binaries, ensure the artifact matches the target host:

bash
file /usr/local/bin/my-service
uname -m

If they differ, rebuild for the correct target or use cross-compilation explicitly. This commonly happens when people build on Apple Silicon and deploy to x86 Linux without setting a target architecture.

ExecStart Is Not a Shell Command Line

Systemd does not parse ExecStart the way an interactive shell does. If you need shell features such as pipes, redirection, or variable expansion, invoke a shell explicitly.

Bad assumption:

ini
ExecStart=python app.py > out.log

Better:

ini
ExecStart=/usr/bin/python3 /opt/app/app.py

Or, if shell behavior is truly required:

ini
ExecStart=/bin/sh -c '/usr/bin/python3 /opt/app/app.py > /tmp/out.log'

Use the shell wrapper only when necessary.

Relative Paths Are Fragile

Services often start with a restricted environment and an unexpected working directory. Use absolute paths in ExecStart, interpreter references, and file arguments.

Better:

ini
WorkingDirectory=/opt/app
ExecStart=/usr/bin/python3 /opt/app/main.py

That removes ambiguity around where files are loaded from.

Practical Recovery Flow

When the error appears:

  1. run file on the target
  2. inspect the first script line if it is text
  3. confirm executable permissions
  4. compare CPU architecture for binaries
  5. remove Windows line endings if applicable
  6. reload systemd and retry

This sequence resolves most cases quickly.

Common Pitfalls

  • Forgetting the shebang on scripts launched directly by ExecStart.
  • Shipping a binary built for the wrong CPU architecture.
  • Editing scripts on Windows and deploying them with carriage-return line endings.
  • Writing ExecStart as if systemd were an interactive shell.
  • Using relative paths and assuming the service starts in the project directory.

Summary

  • 'Exec format error means Linux cannot execute the target file in its current format.'
  • Check file type, shebang, line endings, permissions, and CPU architecture first.
  • Use explicit interpreters for scripts when you want service startup to be unambiguous.
  • Do not assume shell parsing in ExecStart.
  • Diagnose the actual executable path before changing unrelated service settings.

Course illustration
Course illustration

All Rights Reserved.