troubleshooting2025-07-20Β·8Β·2/348

Fixing systemd Service Startup Failures on Ubuntu 22.04

A comprehensive guide to diagnosing and resolving systemd service startup failures on Ubuntu 22.04 LTS, including common error patterns and recovery strategies.

Fixing systemd Service Startup Failures on Ubuntu 22.04

When you migrate from cron-based initialization to systemd services, startup failures can feel cryptic. I encountered this firsthand while deploying a data pipeline on an Ubuntu 22.04 server in Lisbon. The service refused to start, and the logs offered little clarity. This post walks through the diagnosis and resolution process step by step.

Environment

  • OS: Ubuntu 22.04.3 LTS (Jammy Jellyfish)
  • systemd version: 249
  • Service type: Custom Python application managed by systemd
  • Deployment: DigitalOcean droplet, 4GB RAM, 2 vCPUs
$ lsb_release -a
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy

$ systemd --version
systemd 249 (249.11-0ubuntu3.12)

The Problem

After creating a new systemd service unit file for a Python-based data collector, the service refused to start:

$ sudo systemctl start data-collector
Job for data-collector.service failed because the control process exited with error code.
See "systemctl status data-collector.service" and "journalctl -xe" for details.

$ sudo systemctl status data-collector
Γ— data-collector.service - Data Collector Service
     Loaded: loaded (/lib/systemd/system/data-collector.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Sat 2025-07-20 14:23:11 WET; 5s ago
    Process: 12345 ExecStart=/usr/bin/python3 /opt/data-collector/main.py (code=exited, status=1/FAILURE)
   Main PID: 12345 (code=exited, status=1/FAILURE)
        CPU: 234ms

The exit code 1/FAILURE is generic. We need more detail.

Analysis

Step 1: Check the Journal Logs

$ journalctl -u data-collector --no-pager -n 50
-- Logs begin at Sat 2025-07-20 08:00:00 WET, end at Sat 2025-07-20 14:25:00 WET. --
Jul 20 14:23:11 ubuntu systemd[1]: Starting Data Collector Service...
Jul 20 14:23:11 ubuntu python3[12345]: Traceback (most recent call last):
Jul 20 14:23:11 ubuntu python3[12345]:   File "/opt/data-collector/main.py", line 5, in 
Jul 20 14:23:11 ubuntu python3[12345]:     import psycopg2
Jul 20 14:23:11 ubuntu python3[12345]: ModuleNotFoundError: No module named 'psycopg2'

Step 2: Verify the Unit File

$ cat /lib/systemd/system/data-collector.service
[Unit]
Description=Data Collector Service
After=network.target postgresql.service

[Service]
Type=simple
User=datacollector
Group=datacollector
WorkingDirectory=/opt/data-collector
ExecStart=/usr/bin/python3 /opt/data-collector/main.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

The unit file itself looks correct. The issue is that the virtual environment's packages are not being loaded.

Step 3: Identify the Root Cause

The service was running as datacollector user, but the Python packages were installed in a virtual environment under /opt/data-collector/venv. The ExecStart was using the system Python, not the venv Python.

$ sudo -u datacollector /opt/data-collector/venv/bin/python -c "import psycopg2; print('OK')"
OK

The venv Python works when invoked directly. The fix is to point ExecStart to the venv Python binary.

Solution

Option A: Use the Virtual Environment Python

[Service]
Type=simple
User=datacollector
Group=datacollector
WorkingDirectory=/opt/data-collector
ExecStart=/opt/data-collector/venv/bin/python /opt/data-collector/main.py
Restart=on-failure
RestartSec=5
Environment="PATH=/opt/data-collector/venv/bin:/usr/bin:/bin"

Option B: Source an Environment File

Create /etc/data-collector.env:

VIRTUAL_ENV=/opt/data-collector/venv
PATH=/opt/data-collector/venv/bin:$PATH
PYTHONUNBUFFERED=1

Update the unit file:

[Service]
Type=simple
User=datacollector
Group=datacollector
WorkingDirectory=/opt/data-collector
EnvironmentFile=/etc/data-collector.env
ExecStart=/usr/bin/python3 /opt/data-collector/main.py
Restart=on-failure
RestartSec=5

Reload and Test

$ sudo systemctl daemon-reload
$ sudo systemctl start data-collector
$ sudo systemctl status data-collector
● data-collector.service - Data Collector Service
     Loaded: loaded (/lib/systemd/system/data-collector.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2025-07-20 14:30:00 WET; 3s ago
   Main PID: 13001 (python3)
      Tasks: 1 (limit: 4567)
     Memory: 45.2M
        CPU: 1.234s
     CGroup: /system.slice/data-collector.service
             └─13001 /opt/data-collector/venv/bin/python /opt/data-collector/main.py

Enable on Boot

$ sudo systemctl enable data-collector
Created symlink /etc/systemd/system/multi-user.target.wants/data-collector.service β†’ /lib/systemd/system/data-collector.service.

Common Patterns for systemd Startup Failures

Here are the most frequent causes I have encountered:

Error PatternLikely CauseFix
`ModuleNotFoundError`Wrong Python interpreterUse venv Python path
`Permission denied`Incorrect User/GroupCheck file ownership
`No such file or directory`Wrong WorkingDirectory or ExecStartVerify paths exist
`Address already in use`Port conflictStop conflicting process
`Timeout`Service takes too long to startIncrease TimeoutStartSec

Lessons Learned

  1. Always test the ExecStart command manually as the target user before enabling the service.
  2. Use journalctl -u <service> -f to follow logs in real time during debugging.
  3. Set Environment or EnvironmentFile explicitly rather than relying on shell profiles.
  4. Keep unit files in /etc/systemd/system/ for custom services, not /lib/systemd/system/.
  5. Run systemd-analyze verify <unit> to catch syntax errors before starting the service.

This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.