Discussed in https://github.com/ghostty-org/ghostty/discussions/14822
Originally posted by AlJohri October 23, 2026
Issue Description
With gtk-single-instance enabled, launching Ghostty while an instance is already running sometimes does nothing. No window opens, and the launching process exits 0. On my laptop this happens to roughly 1 in 30 Super+Enter presses (Hyprland, xdg-terminal-exec); on a slower machine it is more often.
A busctl monitor on /com/mitchellh/ghostty shows the difference. A launch that works sends org.gtk.Actions.DescribeAll and then org.gtk.Application.Activate. A launch that fails sends DescribeAll and never sends Activate.
The cause: on a remote instance, gio.Application.activate() only queues the Activate call (GLib's g_application_impl_activate is a fire-and-forget g_dbus_connection_call). Then Application.run returns and the process exits, sometimes before the GDBus worker thread writes the message. g_application_run flushes the session bus before it returns (g_application_impl_flush, gio/gapplication.c), but Ghostty runs its own loop and never flushes.
This looks different from #13554, where the request reaches a long-running instance that then makes no surface.
Proposed Fix
Flush the session bus before the remote path returns. With this, the reproduction below loses no activations.
Commit: https://github.com/AlJohri/ghostty/commit/6be6267eff23612158089aa2c5d136821acd9b4b
--- a/src/apprt/gtk/class/application.zig
+++ b/src/apprt/gtk/class/application.zig
@@ -556,6 +556,23 @@ pub const Application = extern struct {
"application is remote, exiting run loop after activation",
.{},
);
+
+ // On a remote instance, activate() only queues an asynchronous
+ // D-Bus call. Flush the connection so that the call is sent
+ // before the process exits.
+ if (self.as(gio.Application).getDbusConnection()) |dbus| {
+ var flush_err: ?*glib.Error = null;
+ if (dbus.flushSync(null, &flush_err) == 0) {
+ if (flush_err) |err| {
+ defer err.free();
+ log.warn(
+ "error flushing D-Bus connection: {s}",
+ .{err.f_message orelse "(unknown)"},
+ );
+ }
+ }
+ }
+
return;
}
Expected Behavior
Each launch of a remote instance opens a window in the primary instance.
Actual Behavior
Some launches send no Activate call. The process exits 0 and no window opens.
Reproduction Steps
The race depends on thread timing, so the reproduction makes the client compete for one CPU core. It does not need a running Ghostty, and it opens no windows: a stand-in primary on a private session bus counts the activations.
fake-primary.py:
import signal
from gi.repository import Gio, GLib
count = 0
app = Gio.Application(application_id="com.mitchellh.ghostty")
def on_activate(_app):
global count
count += 1
def on_term():
print(count, flush=True)
loop.quit()
app.connect("activate", on_activate)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM, on_term)
loop = GLib.MainLoop()
app.register(None)
loop.run()Run from a Wayland session:
taskset -c 0 sh -c 'while :; do :; done' & # keep core 0 busy
dbus-run-session -- sh -c '
python3 fake-primary.py > count.txt & sleep 1
for i in $(seq 200); do taskset -c 0 ghostty --gtk-single-instance=true >/dev/null 2>&1; done
sleep 1; kill -TERM $!; wait'
kill %1
cat count.txt # expect 200Results, 2 runs of 200 launches each, every launch exited 0:
| Build | Activations lost |
|---|---|
main 22f100c | 40, 64 |
main 22f100c + patch | 0, 0 |
| 1.3.1 (nixpkgs) | 69, 106 |
| 1.3.1 (nixpkgs) + patch | 0, 0 |
Without the busy loop, Arch's 1.3.1 build still lost 19 of 200 when pinned to one core.
Ghostty Logs
Nothing from Ghostty points at the failure. The client's output is the same for a launch that works and a launch that fails, and it exits 0.
Ghostty Version
Ghostty 1.3.1+omarchy.3 (Arch), also main 22f100c built with the repo's flakeOS Version Information
Arch Linux, kernel 7.2.8; glib2 2.90.1, gtk4 4.24.1, libadwaita 1.10.0. Also on NixOS (glib 2.88.3).
(Linux only) Display Server
Wayland
(Linux only) Desktop Environment/Window Manager
Hyprland 0.56.2
Minimal Ghostty Configuration
(empty; the bug is in the remote launch path)I used Claude Code to trace the D-Bus traffic, write the reproduction, and draft the patch. I reviewed and edited this text and the patch myself.
Activity
0No activity yet.