Skip to content

Config reload freezes Ghostty indefinitely when the IO mailbox is full #14833

Closed

Description

@jcollie

Discussed in #14825

Originally posted by realfresh October 24, 2026

Issue Description

I came across this issue as I'm building a Ghostty theming application that allows you to live preview your colour, font, and other UI-related changes directly against your running Ghostty instance.

As I was running this app, since it often reloads to preview config edits live, my instance was also running Herdr, which sends 258 colour queries (OSC 10, OSC 11, and OSC 4 for every palette index) after each mode 2031 report and each resize.

From the source, I believe this is what happens:

  1. The io thread handles change_config (Thread.zig:321).
  2. StreamHandler.changeConfig sends color_scheme_report into the io thread's own mailbox (stream_handler.zig:133). This happens even when mode 2031 is off.
  3. The mailbox holds 64 messages (mailbox.zig:15). When it is full, send waits forever (mailbox.zig:95). The io thread is the only reader of that mailbox, so it waits on itself.
  4. Every query reply from io-reader is also a mailbox message, so a burst of queries keeps the mailbox full. After that, the main thread blocks on its next send to the same mailbox: the next reload, or the mouse entering the window.

The code is the same on main at 8ef0ec1. This looks like a regression from #9705, which moved this report from the
surface mailbox to the io mailbox. In 1.2.3, changeConfig still sent it with surfaceMessageWriter. #14245 is a similar hang on a full mailbox, but on the surface-free path, and #14444 does not change this one.

With osc-color-report-format = none, the Herdr case stopped freezing (no freeze in 885 reloads, against freezes after about 180 and 270 without it), which fits: colour queries then get no reply.

AI disclosure: I used Claude Code to investigate this. It read the Ghostty source, wrote the reproduction and drafted this report. I ran the reproduction myself and edited the report.

Expected Behavior

A config reload never freezes Ghostty.

Actual Behavior

Within a few seconds the terminal stops updating. Ghostty then stops responding and needs a force quit. A sample of the hung process (release build, so Ghostty frames are inlined) shows all three threads waiting on a futex:

Thread: main-thread
  closure #1 in AppDelegate.setupSignals()
    Thread.Futex.Deadline.wait
Thread: io
    Thread.Futex.Deadline.wait
Thread: io-reader
    Thread.Futex.Deadline.wait

The log agrees: the second reload is the last thing Ghostty logs, and none of the 27 SIGUSR2 sent over the next 5 seconds appears (log below).

Reproduction Steps

  1. Open Ghostty and run this in it. It writes cursor position queries without pause and reads the replies:

    stty raw -echo; cat >/dev/null &
    q=$(printf '\e[6n%.0s' {1..2000}); while :; do printf %s "$q"; done
  2. From another terminal app, reload Ghostty's config repeatedly:

    while :; do kill -USR2 $(pgrep -nx ghostty); sleep 0.15; done
  3. Ghostty freezes within a few seconds. It froze in 5 of 5 runs.

Neither step alone freezes it. A reload with no config change is enough.

Ghostty Logs

# log stream --level debug during the repro, trimmed to the reloads
13:23:28.960 [ghostty] reloading configuration in response to SIGUSR2
13:23:28.961 [ghostty] config change notification
13:23:28.961 [ghostty] config change notification
13:23:29.121 [ghostty] reloading configuration in response to SIGUSR2
13:23:29.123 [ghostty] config change notification
13:23:29.123 [ghostty] config change notification
# nothing more is logged

Ghostty Version

Ghostty 1.3.1

Version
  - version: 1.3.1
  - channel: stable
Build Config
  - Zig version   : 0.15.2
  - build mode    : .ReleaseFast
  - app runtime   : .none
  - font engine   : .coretext
  - renderer      : renderer.generic.Renderer(renderer.Metal)
  - libxev        : kqueue

OS Version Information

macOS 27.0.1 (26A434)

(Linux only) Display Server

None

(Linux only) Desktop Environment/Window Manager

No response

Minimal Ghostty Configuration

None needed. Reproduced with --config-default-files=false.

Additional Relevant Configuration

Herdr 0.9.5 triggered it in real use. The repro above does not need it.

I acknowledge that:

  • I have reviewed the FAQ and confirm that my issue is NOT among them.
  • I have searched the Ghostty documentation and confirm there doesn't exist a configuration option that solves my issue.
  • I have searched the Ghostty repository (both open and closed Discussions and Issues) and confirm this is not a duplicate of an existing issue or discussion.
  • I have checked the "Preview" tab on all text fields to ensure that everything looks right, and have wrapped all configuration and code in code blocks with a group of three backticks (```) on separate lines.

Activity

  1. added this to the 1.4.0 milestone on Oct 24, 2026
  2. added a commit that references this issue on Oct 26, 2026
    297507f
  3. added a commit that references this issue on Oct 26, 2026
    87b6596
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions