status=203/EXEC в systemd
Код 203/EXEC systemd выдаёт сам, когда добрался до вызова execve() и получил отказ. Это значит, что подготовка запуска прошла, а вот запустить указанную в ExecStart= программу не удалось. Сама программа при этом не выполнила ни одной своей инструкции, поэтому в журнале нет её сообщений — только строка от systemd.
Что это значит
Под кодом 203 скрывается ровно один системный вызов: execve(). systemd подготовил окружение процесса, сменил пользователя, применил ограничения, а затем попросил ядро заменить процесс указанной программой — и получил ошибку. Ядро отказывает по нескольким причинам, и рядом со строкой про EXEC systemd почти всегда печатает ту самую причину от ядра: No such file or directory, Permission denied, Exec format error.
Из-за этого разбор 203/EXEC всегда начинается не с кода, а с приписки к нему. Именно она отличает «файла нет» от «файл есть, но не исполняемый» и от «файл исполняемый, но в нём указан несуществующий интерпретатор».
На каком этапе. Ошибка возникает между подготовкой процесса и первой строкой самой программы. Всё, что настраивается в unit-файле (пользователь, каталог, окружение, ограничения), уже применено успешно.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
В
ExecStart=указан путь, которого нетОпечатка в пути, программа лежит в другом каталоге, каталог с ней смонтирован позже запуска службы или файл удалён при обновлении пакета. Ядро возвращает ENOENT, systemd переводит это в 203/EXEC.
-
Путь относительный, а не абсолютный
systemd не ищет программу в PATH и не имеет «текущего каталога» в привычном смысле. Запись вида
ExecStart=myapp --serveилиExecStart=./serverдля него не имя команды, а несуществующий путь. -
У файла нет права на исполнение
Файл на месте, но без бита x. Так бывает после распаковки архива, копирования через веб-интерфейс, переноса с файловой системы без прав и после
git checkoutв системах, где права не сохраняются. -
В строке
ExecStart=использован синтаксис оболочкиsystemd запускает программу напрямую, без sh. Конвейеры, перенаправления,
&&, подстановки в обратных кавычках и звёздочки в именах файлов не раскрываются: они уходят программе как обычные аргументы, а если с них начинается строка — путь оказывается бессмысленным. -
Скрипт ссылается на интерпретатор, которого нет
При запуске скрипта ядро читает первую строку с
#!и выполняет указанный там интерпретатор. Если путь в ней неверный — например#!/usr/bin/pythonна системе, где есть только python3, — ошибка ENOENT относится к интерпретатору, а не к скрипту. Выглядит это как «файл есть, но systemd говорит, что его нет». -
Файл не той архитектуры или повреждён
Ядро отказывает с
Exec format error, когда файл не является исполняемым для этой платформы: собран под другую архитектуру, скачан не до конца, оказался текстом без строки#!или это библиотека, а не программа.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Показывает строку Process: с полным значением ExecStart и кодом. В той же выдаче видно, дошло ли дело до главного процесса или упало на ExecStartPre.
systemctl status myapp.service -l --no-pagerРядом со строкой про шаг EXEC systemd печатает причину от ядра. Именно она определяет, какая из причин ниже ваша.
journalctl -xeu myapp.service --no-pager -n 50Показывает unit-файл в том виде, в котором его применил systemd, вместе со всеми drop-in из каталогов *.d. Правка, забытая без daemon-reload, сразу видна.
systemctl cat myapp.serviceЗапуск той же программы от того же пользователя вручную. Если так она тоже не запускается, дело не в systemd, и разбираться надо с файлом и правами.
sudo -u app /opt/myapp/bin/server --versionРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
ExecStart= указан путь, которого нет- Почему происходит
- Опечатка в пути, программа лежит в другом каталоге, каталог с ней смонтирован позже запуска службы или файл удалён при обновлении пакета. Ядро возвращает ENOENT, systemd переводит это в 203/EXEC.
- Как проверить
-
Сравните путь из действующего unit-файла с тем, что есть на диске. Важно смотреть именно на действующий файл: правка в /etc/systemd/system могла не примениться без перезагрузки конфигурации.
systemctl cat myapp.service | grep ExecStart ls -l /opt/myapp/bin/server
- Как исправить
-
Поставьте правильный абсолютный путь. Точный путь к программе из системных каталогов показывает
command -v. После правки unit-файла обязательноsystemctl daemon-reload.command -v myapp sudo systemctl daemon-reload && sudo systemctl restart myapp.service
- Почему происходит
- systemd не ищет программу в PATH и не имеет «текущего каталога» в привычном смысле. Запись вида
ExecStart=myapp --serveилиExecStart=./serverдля него не имя команды, а несуществующий путь.
- Как проверить
-
Проверьте, начинается ли значение
ExecStart=с косой черты. Проверка unit-файла на этом сайте отмечает такие строки как ошибку.systemctl cat myapp.service | grep -E "^Exec"
- Как исправить
-
Замените имя команды полным путём. Если программа установлена в нестандартный каталог, путь всё равно пишется целиком — переменную PATH из вашего профиля служба не видит.
ExecStart=/usr/local/bin/myapp --serve
- Почему происходит
- Файл на месте, но без бита x. Так бывает после распаковки архива, копирования через веб-интерфейс, переноса с файловой системы без прав и после
git checkoutв системах, где права не сохраняются.
- Как проверить
-
Посмотрите права: в выводе
ls -lу исполняемого файла должны быть x для владельца и для тех, от чьего имени запускается служба.ls -l /opt/myapp/bin/server sudo -u app test -x /opt/myapp/bin/server && echo исполняемый || echo нет права
- Как исправить
-
Добавьте право на исполнение. Если служба работает от отдельного пользователя, проверьте и права на все каталоги по пути — на каждый нужен бит x, иначе до файла просто не дойти.
sudo chmod 755 /opt/myapp/bin/server
ExecStart= использован синтаксис оболочки- Почему происходит
- systemd запускает программу напрямую, без sh. Конвейеры, перенаправления,
&&, подстановки в обратных кавычках и звёздочки в именах файлов не раскрываются: они уходят программе как обычные аргументы, а если с них начинается строка — путь оказывается бессмысленным.
- Как проверить
-
Поищите в строке запуска символы
|,>,&&,;,$(. Их наличие почти всегда означает, что unit писали как строку в терминале.systemctl cat myapp.service | grep -nE "[|>&;]|\$\("
- Как исправить
-
Вызовите оболочку явно и передайте ей всю команду одной строкой, либо, что надёжнее, перенесите логику в отдельный скрипт и запускайте его.
ExecStart=/bin/sh -c '/opt/myapp/bin/server >> /var/log/myapp.log 2>&1'
- Почему происходит
- При запуске скрипта ядро читает первую строку с
#!и выполняет указанный там интерпретатор. Если путь в ней неверный — например#!/usr/bin/pythonна системе, где есть только python3, — ошибка ENOENT относится к интерпретатору, а не к скрипту. Выглядит это как «файл есть, но systemd говорит, что его нет».
- Как проверить
-
Посмотрите первую строку скрипта и проверьте существование указанного в ней пути.
head -1 /opt/myapp/run.py ls -l /usr/bin/python
- Как исправить
-
Исправьте строку
#!на существующий путь или запускайте интерпретатор явно, указав его вExecStart=первым аргументом.ExecStart=/usr/bin/python3 /opt/myapp/run.py
- Почему происходит
- Ядро отказывает с
Exec format error, когда файл не является исполняемым для этой платформы: собран под другую архитектуру, скачан не до конца, оказался текстом без строки#!или это библиотека, а не программа.
- Как проверить
-
Определите тип файла и сверьте архитектуру с машиной.
file /opt/myapp/bin/server uname -m
- Как исправить
-
Поставьте сборку под нужную архитектуру. Для скриптов добавьте первой строкой
#!/bin/shили#!/usr/bin/env python3.
Пример вывода
Служба с несуществующим путём в ExecStart=. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
× myapp.service - My application
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Mon 2026-09-14 09:12:41 MSK; 3s ago
Process: 4118 ExecStart=/opt/myapp/bin/server --config /etc/myapp.yml (code=exited, status=203/EXEC)
Main PID: 4118 (code=exited, status=203/EXEC)
CPU: 1ms
systemd[4118]: myapp.service: Failed to locate executable /opt/myapp/bin/server: No such file or directory
systemd[4118]: myapp.service: Failed at step EXEC spawning /opt/myapp/bin/server: No such file or directory
systemd[1]: myapp.service: Main process exited, code=exited, status=203/EXEC
systemd[1]: myapp.service: Failed with result 'exit-code'.
Ключевая строка тут не про 203, а про No such file or directory. При запрете доступа на том же месте было бы Permission denied, а при неверной сборке — Exec format error.
Частые вопросы
Почему 203/EXEC, если файл точно на месте и исполняемый?
Чаще всего дело в строке #! внутри скрипта: путь к интерпретатору в ней неверный, и ядро жалуется на него, а не на сам скрипт. Вторая частая причина — запрет доступа не к файлу, а к одному из каталогов по пути: на каждый каталог нужен бит x.
Можно ли по коду понять, что именно случилось?
Нет, 203 сообщает только про отказ execve(). Причину даёт приписка в журнале: No such file or directory, Permission denied, Exec format error. Без неё разбирать бессмысленно.
Почему в терминале команда работает, а служба падает?
В терминале действует ваш PATH, текущий каталог и ваше окружение. У службы нет ничего из этого: путь только абсолютный, окружение задаётся в unit-файле, а пользователь может быть другим.
Связанные ошибки
- status=200/CHDIR в systemd Код 200/CHDIR означает, что systemd не смог перейти в каталог из WorkingDirectory= до запуска программы. Причины и решение.
- status=217/USER в systemd Код 217/USER означает, что systemd не смог определить или сменить пользователя из User=. Разбор причин: пользователя нет, имя недопустимо, конфликт с DynamicUser.
- Exec format error при запуске службы Ошибка формата исполняемого файла: не та архитектура, нет строки #!, повреждённый файл или попытка запустить не программу.
- Permission denied в журнале службы Отказ в доступе у службы systemd: права на файл, каталоги по пути, пользователь службы, параметры изоляции, SELinux и AppArmor.
- No such file or directory в журнале службы Служба не находит файл или каталог. Разбор: путь, момент запуска, изоляция unit-файла, символические ссылки, приватный /tmp.
- status=126 в systemd: файл не исполняется Код 126: команда найдена, но выполнить её нельзя. Отличие от 127 и от 203/EXEC, разбор причин.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Job for … failed because a timeout was exceeded Задание на запуск прервано по таймауту. Как отличить медленный старт от заблокированного и правильно настроить TimeoutStartSec.
Где встречается чаще всего
Источники
-
systemd.exec(5)
Таблица кодов выхода: 203 EXIT_EXEC — отказ системного вызова execve(). -
systemd.service(5)
Требование абсолютного пути в Exec*= и правила разбора строки запуска. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Проверено на сломанном unit: несуществующий путь, файл без бита x, скрипт с неверной строкой #!. В трёх случаях код один, приписка от ядра разная.