Status: CURRENT — RECOVERY WORKAROUND
Last reviewed: 31 August 2026
Applies to: Portainer CE/BE on Docker Standalone when a stack exists in Portainer but its stored Compose file is missingThis is still a real Portainer failure mode. Recent Portainer issues show stacks can become undeletable when the stored
/data/compose/<stack-id>directory or Compose file disappears. This workaround recreates the minimum Portainer expects so the stack can be deleted normally.
Every now and again Portainer manages to get itself into a stupid state where a stack still exists in its database, but the Compose file behind it has disappeared.
You then try to delete the broken stack and Portainer throws something along the lines of:
could not get the contents of the file 'docker-compose.yml'
or
open /data/compose/234/docker-compose.yml:
no such file or directoryExcellent. The stack is broken because the file is missing, and Portainer refuses to delete the broken stack because the file is missing. Very helpful 😂.
Is this still relevant?
Yep.
This bug has been reported in Portainer for years, and there are still current examples. A July 2026 Portainer issue describes a failed Git Pull and redeploy operation leaving the stack’s /data/compose/<id> directory without the Compose file, after which the stack cannot be edited or redeployed normally.
Older reports describe the same basic workaround as this article: recreate the missing directory/file, then let Portainer perform the deletion itself.
Important: we’re touching Portainer’s persistent
/datadirectory directly. Don’t start randomly deleting folders in there because some bloke on the internet — including me — said so. Back up Portainer first 🙂
1. Find the stack ID
The easiest clue is normally the error itself. Portainer may show a path such as:
/data/compose/234/docker-compose.ymlIn that example the stack ID is:
234You may also be able to see the stack ID in the Portainer URL when viewing the stack.
2. Find where Portainer’s /data actually lives
My old article assumed Portainer used the default named volume at:
/var/lib/docker/volumes/portainer_data/_dataThat’s common, but it is not guaranteed. Portainer might be using a different named volume or a bind mount.
Ask Docker where the Portainer container’s /data mount actually points:
docker inspect portainer --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Source}}{{end}}{{end}}'For a standard named volume that may return:
/var/lib/docker/volumes/portainer_data/_dataIf your Portainer container isn’t actually called portainer, find it first:
docker ps --format 'table {{.Names}}\t{{.Image}}' | grep -i portainer3. Back up Portainer before poking it
Set the returned path as a variable:
PORTAINER_DATA="$(docker inspect portainer --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Source}}{{end}}{{end}}')"
echo "$PORTAINER_DATA" Make sure that printed the correct Portainer data directory before continuing.
Then take a quick filesystem backup:
sudo tar -czf "/root/portainer-data-backup-$(date +%Y%m%d-%H%M%S).tar.gz" -C "$PORTAINER_DATA" .For a tiny recovery job this takes bugger-all effort and gives you an escape hatch if your fingers become enthusiastic.
4. Check the Compose storage
List Portainer’s stored stack directories:
sudo ls -lah "$PORTAINER_DATA/compose/" If your broken stack is ID 234, check it directly:
sudo ls -lah "$PORTAINER_DATA/compose/234/" You will normally find one of two things:
- The entire
234directory is missing. - The directory exists but
docker-compose.ymlis missing.
5. Recreate only what Portainer is complaining about
If the whole stack directory is missing:
sudo mkdir -p "$PORTAINER_DATA/compose/234" Now create the missing Compose file:
sudo nano "$PORTAINER_DATA/compose/234/docker-compose.yml" It does not need to recreate your entire original stack if your only goal is to get rid of the dead Portainer record.
I put a single YAML comment in it:
# recovery placeholder so Portainer can delete the broken stackSave the file.
You can do the same thing without opening an editor:
echo '# recovery placeholder so Portainer can delete the broken stack' | sudo tee "$PORTAINER_DATA/compose/234/docker-compose.yml" >/dev/null6. Try deleting the stack again
Go back to:
Portainer → Stacks → broken stack → Delete this stackIf the missing Compose file was the blocker, Portainer should now be able to finish deleting the stale stack record.
That’s it. We essentially gave Portainer the world’s saddest Compose file so it would finally agree to clean up its own mess 😀
What if it complains about stack.env instead?
Another reported version of this bug complains about:
failed to create env file:
open /data/compose/234/stack.env:
no such file or directoryIn that case, recreating the missing stack directory may be enough because Portainer can then create stack.env itself.
If the error specifically says a required file is missing, follow the error rather than blindly manufacturing a dozen random files.
Git-backed stacks are a bit different
If the stack originally came from Git, first consider whether restoring the Compose file/repository path is the cleaner fix.
Portainer’s current Git stack handling still expects the configured Compose path to exist. Renaming/removing that file can leave Portainer unable to redeploy or delete the stack cleanly.
If you only want the stale Portainer entry gone and the Git source is already toast, the placeholder-file recovery above is still useful.
What I would NOT do
- Don’t delete the entire
portainer_datavolume. That’s the nuclear option and wipes Portainer’s persistent state. - Don’t start editing Portainer’s database manually just to remove one broken stack unless you absolutely know what you’re doing.
- Don’t delete random numbered directories from
/data/compose. - Don’t assume the stack ID is the same thing as a Docker container ID.
The goal here is deliberately boring: identify the exact missing stack directory, recreate the minimum expected file, let Portainer delete it normally, fuck off and do something more interesting.
Old command from the original article
The original guide started with:
sudo ls /var/lib/docker/volumes/portainer_data/_data/compose/That is still correct if Portainer uses a Docker named volume called portainer_data. The current article simply discovers the mount first so the same fix also works with custom volumes and bind mounts.
References
- Portainer issue #3343 — missing docker-compose.yml prevents stack deletion
- Portainer issue #9055 — missing stack.env / Compose directory
- Portainer issue #11704 — GitOps stack cannot be removed after Compose file disappears
- Portainer issue #13248 — 2026 failed Git redeploy leaves Compose data broken
- Portainer stack management documentation
A very small fix for a very annoying circular error. Portainer: “I can’t delete the stack because the file doesn’t exist.” Me: “Fine, here’s a fucking comment file.” Portainer: “Oh okay then.” 🙂
