Repository navigation
Linux URL handler desktop entry quotes the Exec path, so xdg-open's generic fallback never launches the AppImage and OAuth callbacks open in the browser instead #16632
Description
Activity
Note
Grok responding on behalf of Julius.
Confirmed on current
main(517188b).Root cause. The URL-handler entry always double-quotes the Exec path, even when the path needs no quoting:
apps/desktop/src/app/DesktopLinuxUrlHandler.ts:74-82:escapeDesktopEntryExecArgumentescapes the reserved characters and then always wraps the value in"...".apps/desktop/src/app/DesktopLinuxUrlHandler.ts:96:renderUrlHandlerDesktopEntrywritesExec=${escapeDesktopEntryExecArgument(execTarget)} %U.- Two places write this entry, so both produce the quoted form:
- the pre-ready path,
apps/desktop/src/app/DesktopPreReadyPlatform.ts:93-104, whereexecTargetis$APPIMAGEorprocess.execPath - the post-ready
writeDesktopEntry,DesktopLinuxUrlHandler.ts:128-146
- the pre-ready path,
The Desktop Entry spec allows the quoted form. xdg-utils'
genericpath insearch_desktop_filedoes not unquote it, though: it runscommand -von the literal"…/t3code.AppImage", skips the handler, and falls back to$BROWSER(xdg-utils #151 and #279). On sway, Hyprland, i3, river and other desktops that xdg-open doesn't recognize, thet3code://callback never reaches the app. GNOME, KDE and COSMIC go throughgio/kde-open, which parse Exec correctly. That explains why #10354 was fixed by the cache refresh alone.The tests currently expect the quoting unconditionally:
DesktopLinuxUrlHandler.test.ts:161-176and:227.Suggested fix direction. Quote the Exec argument only when it contains characters the spec reserves: space, tab, newline,
",',\,`,$,<,>,~,|,&,;,*,?,#,(,). Literal%still needs to be doubled either way. Paths like/home/<user>/.local/bin/t3code.AppImagewould then be written bare and work with the xdg-utils fallback. Paths that really need quoting stay correct for spec-compliant launchers.Update the existing test at
:227to expect the unquoted form for a plain path, and keep the:176case quoted. Both writers go throughrenderUrlHandlerDesktopEntry, so one change covers both.Related.
- [Bug]: Linux AppImage OAuth callback fails until desktop application cache is refreshed #10354 (closed): same symptom, different cause (the MIME cache).
- [Bug]: second-instance handler drops deep-link URL, breaking SSO login when app is already running #5978 (closed): a deep link dropped when the app is already running. Different failure; here the URL never reaches the app.
- Open PR fix(desktop): support Linux distro protocol launchers #8668 changes the Exec target for distro launchers, but it still goes through
escapeDesktopEntryExecArgument, so it doesn't fix this. - Open PR feat(desktop): sign in through the browser, sharing the t3 connect credential #7483 removes this file as part of a larger sign-in rework. It is currently in conflict with
main.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 7, 2026 Confirmed on another setup, with the suggested direction working as a manual workaround.
Symptom. Desktop app, "Sign in to T3 Connect" opens the browser, sign-in completes in the browser, but the app never becomes signed in.
t3 connect statuskept reporting the environment as linked but authorization missing.Environment.
- T3 Code 0.0.46-nightly.20261009.2861 (AppImage), Linux x64, CachyOS kernel 7.2.6
- Desktop: niri (Wayland),
XDG_CURRENT_DESKTOP=niri, no$BROWSERset - Browser: Zen (Firefox fork, native package),
t3codescheme set to "use system default" - xdg-utils 1.2.1
Evidence. The app-written entry
~/.local/share/applications/com.t3tools.T3Code.desktophasExec="~/Applications/T3-Code-0.0.46-nightly.20261009.2861-x86_64.AppImage" %U, andxdg-mime query default x-scheme-handler/t3codereturns it. Reproducing xdg-open's genericsearch_desktop_filecheck on the first word of that Exec line:$ command -v '"/home/<user>/Applications/T3-Code-0.0.46-nightly.20261009.2861-x86_64.AppImage"' (not found)so the generic path skips the handler and falls back to the browser. Network was healthy and the AppImage exists at that path; only the quoting is wrong for this launcher.
Workaround that fixed it. A second, hand-written entry with an unquoted Exec (
Exec=/home/<user>/.local/bin/t3code %U, a tiny script that execs the newest AppImage) was already registered for the scheme. Runningxdg-mime default t3code.desktop x-scheme-handler/t3codeand signing in again completed immediately. Note the app re-runs
xdg-mime default com.t3tools.T3Code.desktop …on every launch (DesktopLinuxUrlHandler.tssetDefaultHandler), so the workaround is reverted at the next start and has to be repeated before each new sign-in.
Diagnosed via
t3 triage, written by Claude (Fable 5.1) in Claude Code on the user's machine.
What happened
Desktop app on Linux (AppImage). Clicking Sign in (T3 Connect) opens the Clerk widget; choosing Google and completing the account picker ends in the browser asking to open the callback with xdg-open. Confirming does nothing useful: a second, empty browser window opens with the
t3code://URL, the in-app Clerk widget keeps spinning, and the user is never signed in. CLI login (bunx t3) works, so the account itself is fine.Diagnosis
DesktopLinuxUrlHandler.tswrites the URL-handler desktop entry with a double-quoted Exec path (escapeDesktopEntryExecArgumentwraps every value in"..."):The Desktop Entry spec allows this, but xdg-utils' shell fallback does not implement Exec quoting. On any desktop that xdg-open does not recognize (sway, Hyprland, i3, river, and so on) it takes the
genericpath, andsearch_desktop_filedoes:command -vfails on the quoted string, the handler is skipped, and xdg-open falls back to$BROWSER/ the default web browser, which is why a second browser window opens with thet3code://URL. The running app never receives the callback, so the OAuth flow never completes. This is xdg-utils issues #151 and #279 (see Related); it has been open since 2019, so T3 cannot rely on it being fixed downstream.Everything else in the registration chain was fine on this machine: the entry exists and points at the current AppImage,
mimeinfo.cachelists it forx-scheme-handler/t3code, andxdg-mime query default x-scheme-handler/t3codereturnscom.t3tools.T3Code.desktop. Removing the quotes from Exec is the only change needed for xdg-open to launch it (verified below).Desktops where xdg-open delegates to
gio openorkde-openparse Exec correctly, which is why GNOME/KDE/COSMIC users are not hit and why #10354 was solved by the cache refresh alone.Possible fix direction: only quote the Exec argument when it contains characters that need it (spaces, quotes,
$, backticks,%), or point Exec at a small wrapper script at a quote-free path. Not patched locally.Steps to reproduce
Standalone, no T3 needed (xdg-utils 1.2.1, with
XDG_CURRENT_DESKTOPset to something xdg-open does not know, e.g.sway):Output:
In T3 Code:
generic(sway here).~/.local/share/applications/com.t3tools.T3Code.desktopwith the quoted Exec.t3code://app/...with xdg-open. Confirm.t3code://URL; the app never receives it and the Clerk widget spins forever.Version
0.0.46-nightly.20261004.2657 (tag
v0.0.46-nightly.20261004.2657, commitefecd3cf)Environment
NixOS, Linux 6.18.33 x86_64, sway (Wayland), xdg-utils 1.2.1, AppImage launched through nixpkgs
appimage-run(bubblewrap FHS sandbox), default browser Helium 0.10.7.1 (Chromium based). Node v26.8.2.Evidence
Related issues
mimeinfo.cache(fix(desktop): make Linux URL handlers discoverable with the app icon #8673). Not a duplicate: here the cache and the default are already correct and the failure is xdg-open's Exec parsing on the generic path.Fix applied or workaround
Nothing changed on the machine by triage. Workaround for the user: an extra handler desktop entry with an unquoted Exec, set as the
x-scheme-handler/t3codedefault inmimeapps.list. Because the app rewrites its own entry on every start, the workaround has to live in a separate file.A second, machine-specific problem was also found and is not part of this issue: the user's default browser runs through a wrapper that sets
HOME/XDG_DATA_HOMEto a different directory, so the xdg-open it spawns does not see~/.local/share/applicationsat all.Filed by
Claude Fable 5.1 (Claude Code) via
t3 triage, on behalf of the user.