Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for Podman By James Joyner IV · · 10 min read Last reviewed Jul 2026

Podman Error: Quadlet Unit 'Failed to start' as a systemd Service

Quick answer

Fix Podman Quadlet units that fail to start: run the generator with -dryrun, reload the user daemon, correct [Container] keys, unit naming, and enable-linger for boot.

  • #podman
  • #containers
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this Podman error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Exact Error Message

$ systemctl --user start myapp.service
Failed to start myapp.service: Unit myapp.service not found.

Or, when the unit does exist but the generated container fails at runtime:

$ systemctl --user status myapp.service
● myapp.service
     Loaded: loaded (/home/deploy/.config/containers/systemd/myapp.container; generated)
     Active: failed (Result: exit-code) since Sun 2026-07-19 09:41:07 UTC
    Process: 20114 ExecStart=/usr/bin/podman run --name=systemd-myapp ... (code=exited, status=125)

podman[20114]: Error: short-name "myapp:latest" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"

What It Means

Quadlet is a systemd generator, not a service manager. You write a declarative .container, .volume, .network, .pod, or .kube file, and at daemon-reload time systemd runs /usr/libexec/podman/quadlet, which translates that file into an ordinary .service unit in a runtime directory. Nothing is watching your file otherwise. This single fact explains most Quadlet failures: if the generator did not run, or ran and rejected your file, systemd has no unit to start, and you get the flat Unit not found message with no hint that a Quadlet file even exists.

The second class of failure is the opposite — generation succeeded, so a real .service exists, and the failure is a plain podman run error surfaced through systemd. Exit status 125 is Podman refusing to start the container: an image that cannot be pulled, an unqualified short name with no search registry, a port already bound, a volume path that does not exist, or a dependency that has not started yet. The distinction between “no unit was generated” and “the unit ran and Podman failed” is the first thing to establish, and systemctl --user status tells you immediately: a Loaded: line pointing at your .container file means generation worked.

Common Causes

  • The file is in the wrong directory — rootless units must live in ~/.config/containers/systemd/, rootful ones in /etc/containers/systemd/.
  • systemctl --user daemon-reload was not run after creating or editing the file, so no unit was regenerated.
  • A syntax error or unknown key made the generator skip the file entirely.
  • Image= is missing, misspelled, or uses an unqualified short name that cannot be resolved.
  • The unit has no [Install] section, so systemctl enable fails and it never starts at boot.
  • Lingering is not enabled for the user, so rootless units only run while an interactive session exists.

Diagnostic Commands

Confirm whether a unit was generated at all, and from which source file:

systemctl --user list-unit-files 'myapp*'
systemctl --user status myapp.service

Run the generator by hand — this is the highest-value Quadlet debugging command, because it prints the exact unit it would produce or the parse error that stopped it:

/usr/libexec/podman/quadlet -dryrun -user

For rootful units, drop -user:

sudo /usr/libexec/podman/quadlet -dryrun

Read the generator’s own complaints, which systemd logs during the reload:

journalctl --user -b | grep -i quadlet
journalctl --user -u myapp.service -n 100 --no-pager

Verify the file is where the generator actually looks, and that its name is right:

ls -l ~/.config/containers/systemd/
podman --version

Step-by-Step Resolution

  1. Put the file in the correct directory with the correct extension, and get the unit-name mapping right. myapp.container generates myapp.service; data.volume generates data-volume.service and a Podman volume named systemd-data. You always systemctl the generated .service name, never the .container name:
mkdir -p ~/.config/containers/systemd
$EDITOR ~/.config/containers/systemd/myapp.container
  1. Write a minimal, valid unit. Image= is mandatory and should be fully qualified; the [Install] section is what makes enable work:
# ~/.config/containers/systemd/myapp.container
[Unit]
Description=My application container
After=network-online.target

[Container]
Image=docker.io/library/nginx:1.27
ContainerName=myapp
PublishPort=8080:80
Volume=%h/appdata:/usr/share/nginx/html:Z,ro
Environment=TZ=UTC

[Service]
Restart=always
TimeoutStartSec=300

[Install]
WantedBy=default.target

Note PublishPort=8080:80 rather than a privileged port — a rootless container cannot bind below 1024 by default. See Podman error: rootless bind privileged port if you need port 80 itself.

  1. Reload so the generator runs, then verify a unit actually appeared. Editing the file and calling start without a reload is the single most common Quadlet mistake:
systemctl --user daemon-reload
systemctl --user list-unit-files myapp.service

If the unit still does not exist, the generator rejected your file — go straight to -dryrun:

/usr/libexec/podman/quadlet -dryrun -user 2>&1 | head -50
  1. Fix image resolution. An unqualified short name fails non-interactively because there is no TTY to prompt for a registry choice. Always fully qualify Image=:
# wrong
Image=nginx:latest

# right
Image=docker.io/library/nginx:1.27

This is the same root cause covered in Podman error: short-name resolution with no TTY. Pre-pulling the image also removes a slow first start from the equation:

podman pull docker.io/library/nginx:1.27
  1. Express dependencies as Quadlet resources rather than hand-written After= lines, so ordering and naming stay consistent. Referencing a .volume or .network file by name makes Quadlet emit the correct Requires=/After= for you:
# ~/.config/containers/systemd/appdata.volume
[Volume]
VolumeName=appdata

# ~/.config/containers/systemd/backend.network
[Network]
NetworkName=backend

# in myapp.container
[Container]
Image=docker.io/library/nginx:1.27
Volume=appdata.volume:/data:Z
Network=backend.network
  1. Enable it, and turn on lingering so it survives logout and starts at boot. Without lingering, the user manager is torn down when your last session ends and the container goes with it:
loginctl enable-linger "$USER"
systemctl --user enable --now myapp.service
systemctl --user is-enabled myapp.service
podman ps --filter name=myapp

Confirm lingering took effect with loginctl show-user "$USER" --property=Linger, which must print Linger=yes.

Prevention

  • Keep Quadlet files in version control and deploy them with a step that always runs systemctl --user daemon-reload afterwards.
  • Fully qualify every Image= value so image resolution never depends on registry search order.
  • Run /usr/libexec/podman/quadlet -dryrun -user in CI to catch parse errors before they reach a host.
  • Always include [Install] WantedBy=default.target, otherwise enable is a silent no-op for boot-time start.
  • Enable lingering as part of host provisioning for any user that runs rootless services.
  • Prefer .volume and .network units over ad-hoc host paths so dependency ordering is generated rather than hand-maintained.
  • Error: short-name did not resolve to an alias — unqualified image reference with no search registry; fully qualify Image=.
  • Error: cannot listen on the TCP port: bind: permission denied — a rootless unit publishing a port below 1024.
  • Error: netavark: IO error — the container network could not be set up; see Podman error: netavark IO error.
  • Error: container has dependent containers — a teardown ordering problem between related units; see Podman error: container has dependent containers.

Frequently Asked Questions

Why does systemctl --user start myapp.container say the unit is not found? Because .container is the Quadlet source file, not a systemd unit. The generator turns it into myapp.service, and that is the name systemd knows. Drop the .container extension when you start, stop, enable, or check status.

I edited the file but nothing changed — why? Quadlet only runs during a daemon reload. Until you run systemctl --user daemon-reload (or sudo systemctl daemon-reload for rootful units), systemd keeps serving the previously generated unit. Reload after every edit, then restart the service.

How do I see the actual podman run command Quadlet builds? Run /usr/libexec/podman/quadlet -dryrun -user. It prints each generated unit in full, including the complete ExecStart= line, without writing anything to disk. This is the fastest way to confirm that a Volume= or PublishPort= key translated the way you expected.

My rootless container dies when I log out — is that a Quadlet bug? No, it is the default systemd user-session lifecycle. Run loginctl enable-linger "$USER" so the user manager persists across logouts and starts at boot. Without it, WantedBy=default.target only takes effect once you log in. For more container fixes, see the Podman guides.

Free download · 368-page PDF

Fixed it? Get 500 Podman & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.