Скрипт работает в терминале, а под systemd не находит файл. Почему?

Представим: app.py и config.json лежат в /opt/mybot. При запуске из этого каталога всё работает, а системный сервис падает с FileNotFoundError.

Причина может быть в такой строке:

with open("config.json", encoding="utf-8") as file:
    ...

Относительный путь отсчитывается от рабочей директории процесса. Даже абсолютный путь к app.py в ExecStart не означает, что systemd перейдёт в каталог скрипта.

У обычного системного сервиса без WorkingDirectory рабочая директория по умолчанию — /. У пользовательского сервиса, управляемого через systemctl --user, — домашний каталог пользователя. Указание User= в системном сервисе само по себе рабочую директорию не меняет.

Для диагностики можно временно добавить перед открытием файла:

from pathlib import Path
import logging

logging.warning(
    "cwd=%s; config=%s",
    Path.cwd(),
    Path("config.json").resolve(),
)

Так в журнале будет видно, какой путь использует программа.

Если приложение должно запускаться из своего каталога, укажите его в существующем unit-файле:

[Service]
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/app.py

После изменения системного unit-файла:

sudo systemctl daemon-reload
sudo systemctl restart mybot.service

Другой вариант — привязать путь к файлу скрипта, если конфигурация по устройству проекта лежит рядом с ним:

from pathlib import Path

config_path = Path(__file__).resolve().parent / "config.json"

with config_path.open(encoding="utf-8") as file:
    ...

Это устраняет зависимость данного пути от рабочей директории. Если ошибка остаётся, нужно проверить существование файла, права пользователя сервиса и ограничения доступа в unit-файле.

Итог: расположение скрипта и рабочая директория процесса — разные вещи. Явная точка отсчёта для путей делает запуск предсказуемее. Расскажите, продолжат ли работать ваши скрипты, если запустить их из другого каталога?