SUMMARY DBus objects under /org/freedesktop/portal/desktop/request cannot be introspected. The org.freedesktop.DBus.Introspectable.Introspect RPC hangs for ever. This breaks dbus tools that scan the bus for objects and their APIs. I've reproduced this with the D-Bus client library I'm writing, D-Spy (GUI debugger) and the upstream dbus-send(1) tool. STEPS TO REPRODUCE 1. Do something that creates a portal request. I ran Firefox in a flatpak and played a video, which triggers an inhibit portal request. 2. Run: dbus-send --session --dest=org.freedesktop.impl.portal.desktop.kde --type=method_call --print-reply /org/freedesktop/portal/desktop/request org.freedesktop.DBus.Introspectable.Introspect 3. In the response, look for the child node object, and continue traversing down the object tree until you reach a request object. For example, in my case, the inhibit request object looks like: /org/freedesktop/portal/desktop/request/1_61/t/2275739744 3. Run: dbus-send --session --dest=org.freedesktop.impl.portal.desktop.kde --type=method_call --print-reply REQUEST_PATH_HERE org.freedesktop.DBus.Introspectable.Introspect OBSERVED RESULT The introspection request never gets a response, it just hangs until the object is destroyed (e.g. in my repro case, by pausing the video playback which deletes the inhibit request). EXPECTED RESULT The introspection request should succeed or fail promptly, not hang for ever. SOFTWARE/OS VERSIONS Linux/KDE Plasma: Fedora Linux 41 (kernel 6.12.9-200.fc41.x86_64, x86_64, wayland session) KDE Plasma Version: 6.2.5 KDE Frameworks Version: 6.10.0 Qt Version: 6.8.1 DBus implementation: dbus-broker v36 ADDITIONAL INFORMATION I am not at all familiar with KDE source code and conventions, but I traced the misbehaving D-Bus object to https://github.com/KDE/xdg-desktop-portal-kde/blob/master/src/request.cpp , which I notice has a custom introspect implementation that returns a raw XML string snippet. I don't see anything obviously wrong with the implementation, assuming that QDBus actually calls the method when appropriate. I see that Request::handleMessage returns true unconditionally for all method calls, even for calls that it doesn't handle. If QDBus first offers the introspection request to handleMessage before falling back to introspect, that would explain the hang. IIUC, returning true without responding to method calls tells QDBus that this message has been consumed and that it should not do anything else. That would match the behavior I'm observing.
Yup, confirmed, looking at QDBus source code: https://github.com/qt/qtbase/blob/dev/src/dbus/qdbusintegrator.cpp#L1447 When the message is routed to a virtual object, handleMessage gets the first look. If it returns true, that's the end of processing. If it returns false, _then_ QDBus calls activateInternalFilters (https://github.com/qt/qtbase/blob/dev/src/dbus/qdbusintegrator.cpp#L1391), which is where the call to introspect happens. So, Request::handleMessage is accidentally suppressing all the "builtin" DBus interfaces, including introspection. This should be an easy fix, assuming I can figure out how to test a custom build of the portal service...
I always wondered why the requests are virtual objects in the first place and not normal adaptors.