Flatpak version
1.18.2 (Arch 1:1.18.2-1), running with bubblewrap 0.12.0 (0.12.0-1)
What Linux distribution are you using?
Arch Linux
Linux distribution version
Rolling; uname -a → Linux omarchy 7.2.5-3-omarchy #1 SMP PREEMPT_DYNAMIC ... x86_64 GNU/Linux (Omarchy 4.0.4)
What architecture are you using?
x86_64
How to reproduce
Any app whose metadata grants --filesystem=xdg-run/doc fails before the app is reached. It is not app-specific — Flatpak's own sandbox machinery reproduces it with no app involved:
flatpak run --filesystem=xdg-run/doc --command=sh org.gnome.Platform//48 -c true
# → bwrap: Can't mount on symlink destination /run/user/1000/doc
Denying the permission collides in the same place, so there is no override-based workaround:
flatpak run --nofilesystem=xdg-run/doc --command=sh org.gnome.Platform//48 -c true
# → bwrap: Destination is not a directory /run/user/1000/doc
A real-world case: com.pieces.pfd (Pieces Desktop, from the official pieces-flatpak remote) grants home;xdg-documents;xdg-run/pipewire-0;xdg-run/doc, and cannot be launched at all:
flatpak run com.pieces.pfd
# → bwrap: Can't mount on symlink destination /run/user/1000/doc
com.pieces.os from the same remote does not grant xdg-run/doc and starts fine, which is consistent with the analysis below.
Expected Behavior
An app that grants xdg-run/doc starts, and reaches the document portal exactly as an app without that grant does.
Actual Behavior
Sandbox setup aborts with bwrap: Can't mount on symlink destination /run/user/1000/doc (Flatpak 1.18.2 + bubblewrap 0.12.0). With --nofilesystem=xdg-run/doc instead: bwrap: Destination is not a directory /run/user/1000/doc.
flatpak run -vv com.pieces.pfd shows the two halves colliding:
F: Trying to export read/write: /run/user/1000/doc
F: /run/user/1000/doc is not a symlink
F: Will export read/write: /run/user/1000/doc
...
F: --bind
F: /run/user/1000/doc/by-app/com.pieces.pfd
F: /run/flatpak/doc
...
F: Running 'bwrap --args 80 -- pieces-for-developers.sh'
bwrap: Can't mount on symlink destination /run/user/1000/doc
Additional Information
Root cause. Inside every sandbox, /run/user/$UID/doc is a symlink, not a directory:
$ flatpak run --command=sh org.gnome.Platform//48 -c 'ls -la /run/user/1000/doc'
lrwxrwxrwx 1 leonard leonard 17 /run/user/1000/doc -> ../../flatpak/doc
That is by design: add_document_portal_args() in common/flatpak-run.c binds <portal-mount>/by-app/<app_id> onto /run/flatpak/doc and then calls flatpak_bwrap_add_runtime_dir_member (bwrap, "doc") (~lines 1900–1946, called from ~line 3842), which is what materialises /run/user/$UID/doc as a symlink to ../../flatpak/doc.
When the app also grants xdg-run/doc, FlatpakExports (via common/flatpak-exports.c) binds the host's /run/user/$UID/doc (the document-portal FUSE mount) onto that same sandbox path. mount(2) follows a symlink, which is why this worked with bubblewrap ≤ 0.11 — and bubblewrap 0.12.0, the release fixing CVE-2026-87766 / GHSA-pxhw-h44j-8pfx by resolving setup paths with openat2(RESOLVE_IN_ROOT), now refuses to mount over a symlink at all. Note the host side looks fine to Flatpak's export logic (path_is_symlink() checks the host path, which is a real directory there), so the collision is only visible to bwrap.
This is not Ubuntu's backported patch (containers/bubblewrap#801, closed wontfix): that is a different failure (ELOOP on /var/run) in older Ubuntu packages. Here both packages are the current upstream releases, and bubblewrap's refusal is the intended hardening — so Flatpak appears to be the side that needs to adapt.
Suggested direction (upstream's call). Either skip the explicit xdg-run/doc export when the destination is the document-portal path (the runtime-dir member symlink plus the /run/flatpak/doc bind already give the app the per-app portal view), or stop exposing /run/user/$UID/doc as a symlink so an export can land on it. Ordering the symlink creation after the exports does not help on its own, since the export still cannot mount over an existing symlink.
User-side workaround used here (a runtime-directory hack, not a fix): pre-create the per-app runtime-dir entry as a real directory before launching, so the export lands on a directory. Flatpak only warns and proceeds:
F: /run/user/1000/.flatpak/com.pieces.pfd/xdg-run/doc is not a symlink to "../../flatpak/doc" as expected: readlinkat: Invalid argument
The app then starts normally and registers with its local engine over localhost:39300.
Versions for the record. flatpak --version → Flatpak 1.18.2; bwrap --version → bubblewrap 0.12.0; flatpak list --app → com.pieces.os, com.pieces.pfd (user installation, pieces-flatpak remote); xdg-desktop-portal 1.22.1 with xdg-document-portal.service active and /run/user/1000/doc mounted as fuse.portal.
Flatpak version
1.18.2 (Arch
1:1.18.2-1), running with bubblewrap 0.12.0 (0.12.0-1)What Linux distribution are you using?
Arch Linux
Linux distribution version
Rolling;
uname -a→Linux omarchy 7.2.5-3-omarchy #1 SMP PREEMPT_DYNAMIC ... x86_64 GNU/Linux(Omarchy 4.0.4)What architecture are you using?
x86_64
How to reproduce
Any app whose metadata grants
--filesystem=xdg-run/docfails before the app is reached. It is not app-specific — Flatpak's own sandbox machinery reproduces it with no app involved:Denying the permission collides in the same place, so there is no override-based workaround:
A real-world case:
com.pieces.pfd(Pieces Desktop, from the officialpieces-flatpakremote) grantshome;xdg-documents;xdg-run/pipewire-0;xdg-run/doc, and cannot be launched at all:flatpak run com.pieces.pfd # → bwrap: Can't mount on symlink destination /run/user/1000/doccom.pieces.osfrom the same remote does not grantxdg-run/docand starts fine, which is consistent with the analysis below.Expected Behavior
An app that grants
xdg-run/docstarts, and reaches the document portal exactly as an app without that grant does.Actual Behavior
Sandbox setup aborts with
bwrap: Can't mount on symlink destination /run/user/1000/doc(Flatpak 1.18.2 + bubblewrap 0.12.0). With--nofilesystem=xdg-run/docinstead:bwrap: Destination is not a directory /run/user/1000/doc.flatpak run -vv com.pieces.pfdshows the two halves colliding:Additional Information
Root cause. Inside every sandbox,
/run/user/$UID/docis a symlink, not a directory:That is by design:
add_document_portal_args()incommon/flatpak-run.cbinds<portal-mount>/by-app/<app_id>onto/run/flatpak/docand then callsflatpak_bwrap_add_runtime_dir_member (bwrap, "doc")(~lines 1900–1946, called from ~line 3842), which is what materialises/run/user/$UID/docas a symlink to../../flatpak/doc.When the app also grants
xdg-run/doc,FlatpakExports(viacommon/flatpak-exports.c) binds the host's/run/user/$UID/doc(the document-portal FUSE mount) onto that same sandbox path.mount(2)follows a symlink, which is why this worked with bubblewrap ≤ 0.11 — and bubblewrap 0.12.0, the release fixing CVE-2026-87766 / GHSA-pxhw-h44j-8pfx by resolving setup paths withopenat2(RESOLVE_IN_ROOT), now refuses to mount over a symlink at all. Note the host side looks fine to Flatpak's export logic (path_is_symlink()checks the host path, which is a real directory there), so the collision is only visible to bwrap.This is not Ubuntu's backported patch (containers/bubblewrap#801, closed
wontfix): that is a different failure (ELOOPon/var/run) in older Ubuntu packages. Here both packages are the current upstream releases, and bubblewrap's refusal is the intended hardening — so Flatpak appears to be the side that needs to adapt.Suggested direction (upstream's call). Either skip the explicit
xdg-run/docexport when the destination is the document-portal path (the runtime-dir member symlink plus the/run/flatpak/docbind already give the app the per-app portal view), or stop exposing/run/user/$UID/docas a symlink so an export can land on it. Ordering the symlink creation after the exports does not help on its own, since the export still cannot mount over an existing symlink.User-side workaround used here (a runtime-directory hack, not a fix): pre-create the per-app runtime-dir entry as a real directory before launching, so the export lands on a directory. Flatpak only warns and proceeds:
The app then starts normally and registers with its local engine over
localhost:39300.Versions for the record.
flatpak --version→Flatpak 1.18.2;bwrap --version→bubblewrap 0.12.0;flatpak list --app→com.pieces.os,com.pieces.pfd(user installation,pieces-flatpakremote); xdg-desktop-portal 1.22.1 withxdg-document-portal.serviceactive and/run/user/1000/docmounted asfuse.portal.