Issue Description
Quadlet related files within the .app file are attempted to be removed multiple times, not just once.
Steps to reproduce the issue
1 - Install a quadlet:
> ./bin/podman quadlet install ../homelab/quadlets/nginx-test/
/home/kavish/.config/containers/systemd/nginx-test-2.container
/home/kavish/.config/containers/systemd/nginx-test.container
Content of quadlet files:
> cat /home/kavish/.config/containers/systemd/nginx-test.container
[Container]
Image=nginx:mainline-alpine
ContainerName=nginx-test
PublishPort=8282:80
[Service]
Restart=always
[Install]
WantedBy=default.target
> cat /home/kavish/.config/containers/systemd/nginx-test-2.container
[Container]
Image=nginx:mainline-alpine
ContainerName=nginx-test-2
PublishPort=8383:80
[Service]
Restart=always
[Install]
WantedBy=default.target
3 - I added print statements at key locations in the QuadletRemove function to debug the process. When running podman quadlet rm .nginx-test.app, the output showed that the same quadlet and .app files were being scheduled for removal multiple times. This confirmed that the repeated removal attempts were happening internally, even though the user does not see these duplicates in the normal output. But it does lead to redundant operations:
> ./bin/podman quadlet rm .nginx-test.app
Entering QuadletRemove
QUADLETS ARGUMENTS: []string{".nginx-test.app"}
Found .app file: .nginx-test.app; contains files: [nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container]; found in map: true
Processing .app file: .nginx-test.app
Files included in .app: [nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container nginx-test-2.container nginx-test.container]
quadlets after All option: []string{"nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container", "nginx-test-2.container", "nginx-test.container"}
allQuadletPaths has 36 files: [/home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container /home/kavish/.config/containers/systemd/nginx-test-2.container /home/kavish/.config/containers/systemd/nginx-test.container]
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
before range removeList files: [.nginx-test.app]
inside range removelist: Removing .app file (or asset): .nginx-test.app
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
nginx-test-2.container
nginx-test.container
4 - To fix the issue, I introduced a map[string]struct{} to keep track of which files had already been scheduled for removal. Each time we process a quadlet or app file, we check if it's present in the map before adding it to the removal list. This way, every file is only deleted once, preventing duplicate attempts and making the removal logic much cleaner, without cluttering up the logs(if configured).
I have a fix ready and will open a PR soon. I’ll update this issue once the PR is up.
Describe the results you received
The removal logic for .app expansion does not deduplicate quadlet and related files before removal, causing repeated attempts on the same files. The repeated removal attempts are not visible to the user; they occur internally during the removal process. The removal operations do not cause user facing errors, but they result in unnecessary deletion logic during quadlet removal.
Describe the results you expected
Each quadlet unit and related files grouped under the .app file should be deleted once, not multiple times.
podman info output
host:
arch: arm64
buildahVersion: 1.42.0
cgroupControllers:
- cpu
- memory
- pids
cgroupManager: cgroupfs
cgroupVersion: v2
conmon:
package: conmon-2.1.13-2.fc43.aarch64
path: /usr/bin/conmon
version: 'conmon version 2.1.13, commit: '
cpuUtilization:
idlePercent: 95.86
systemPercent: 0.92
userPercent: 3.22
cpus: 2
databaseBackend: sqlite
distribution:
distribution: fedora
variant: server
version: "43"
emulatedArchitectures:
- linux/386
- linux/amd64
- linux/arm64be
- linux/loong64
- linux/mips
- linux/mips64
- linux/ppc
- linux/ppc64
- linux/ppc64le
- linux/riscv32
- linux/riscv64
- linux/s390x
eventLogger: file
freeLocks: 2047
hostname: homelab-testing
idMappings:
gidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 524288
size: 65536
uidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 524288
size: 65536
kernel: 6.17.8-300.fc43.aarch64
linkmode: dynamic
logDriver: journald
memFree: 564088832
memTotal: 2036322304
networkBackend: netavark
networkBackendInfo:
backend: netavark
default_network: podman
dns:
package: aardvark-dns-1.17.0-1.fc43.aarch64
path: /usr/libexec/podman/aardvark-dns
version: aardvark-dns 1.17.0
package: netavark-1.17.0-1.fc43.aarch64
path: /usr/libexec/podman/netavark
version: netavark 1.17.0
ociRuntime:
name: crun
package: crun-1.25-1.fc43.aarch64
path: /usr/bin/crun
version: |-
crun version 1.25
commit: d9a0adce065c7747ab88ea6ccc42b15a626e08e1
rundir: /run/user/1000/crun
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +LIBKRUN +WASM:wasmedge +YAJL
os: linux
pasta:
executable: /usr/bin/pasta
package: passt-0^20250919.g623dbf6-1.fc43.aarch64
version: |
pasta 0^20250919.g623dbf6-1.fc43.aarch64-pasta
Copyright Red Hat
GNU General Public License, version 2 or later
<https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
remoteSocket:
exists: true
path: /run/user/1000/podman/podman.sock
rootlessNetworkCmd: pasta
security:
apparmorEnabled: false
capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
rootless: true
seccompEnabled: true
seccompProfilePath: /usr/share/containers/seccomp.json
selinuxEnabled: true
serviceIsRemote: false
slirp4netns:
executable: ""
package: ""
version: ""
swapFree: 1963204608
swapTotal: 2035281920
uptime: 2h 5m 57.00s (Approximately 0.08 days)
variant: v8
plugins:
authorization: null
log:
- k8s-file
- none
- passthrough
network:
- bridge
- macvlan
- ipvlan
volume:
- local
registries:
search:
- registry.fedoraproject.org
- registry.access.redhat.com
- docker.io
store:
configFile: /home/kavish/.config/containers/storage.conf
containerStore:
number: 1
paused: 0
running: 0
stopped: 1
graphDriverName: overlay
graphOptions: {}
graphRoot: /home/kavish/.local/share/containers/storage
graphRootAllocated: 16039018496
graphRootUsed: 8429662208
graphStatus:
Backing Filesystem: xfs
Native Overlay Diff: "true"
Supports d_type: "true"
Supports shifting: "false"
Supports volatile: "true"
Using metacopy: "false"
imageCopyTmpDir: /var/tmp
imageStore:
number: 2
runRoot: /run/user/1000/containers
transientStore: false
volumePath: /home/kavish/.local/share/containers/storage/volumes
version:
APIVersion: 6.0.0-dev
Built: 1764654652
BuiltTime: Tue Dec 2 09:50:52 2025
GitCommit: 3681055601c5c2a882fc6773a2fc72ef6eb1dadf-dirty
GoVersion: go1.25.4 X:nodwarf5
Os: linux
OsArch: linux/arm64
Version: 6.0.0-dev
Podman in a container
No
Privileged Or Rootless
Rootless
Upstream Latest Release
Yes
Additional environment details
Additional environment details
Additional information
Additional information like issue happens only occasionally or issue happens with a particular architecture or on a particular setting
Issue Description
Quadlet related files within the .app file are attempted to be removed multiple times, not just once.
Steps to reproduce the issue
1 - Install a quadlet:
Content of quadlet files:
3 - I added print statements at key locations in the QuadletRemove function to debug the process. When running
podman quadlet rm .nginx-test.app, the output showed that the same quadlet and .app files were being scheduled for removal multiple times. This confirmed that the repeated removal attempts were happening internally, even though the user does not see these duplicates in the normal output. But it does lead to redundant operations:4 - To fix the issue, I introduced a
map[string]struct{}to keep track of which files had already been scheduled for removal. Each time we process a quadlet or app file, we check if it's present in the map before adding it to the removal list. This way, every file is only deleted once, preventing duplicate attempts and making the removal logic much cleaner, without cluttering up the logs(if configured).Describe the results you received
The removal logic for
.appexpansion does not deduplicate quadlet and related files before removal, causing repeated attempts on the same files. The repeated removal attempts are not visible to the user; they occur internally during the removal process. The removal operations do not cause user facing errors, but they result in unnecessary deletion logic during quadlet removal.Describe the results you expected
Each quadlet unit and related files grouped under the
.appfile should be deleted once, not multiple times.podman info output
Podman in a container
No
Privileged Or Rootless
Rootless
Upstream Latest Release
Yes
Additional environment details
Additional environment details
Additional information
Additional information like issue happens only occasionally or issue happens with a particular architecture or on a particular setting