Patching a Window Restoration Bug in ChatGPT Using Codex
On my MacBook, I keep windows maximized for almost all apps most of the time. Not macOS fullscreen, just the regular maximized window that fills the available space between the menu bar and the Dock. For ChatGPT, I used the native macOS app, and for coding I used the Codex app. But some time ago OpenAI unified them into the new ChatGPT desktop app, renamed the previous native app to ChatGPT Classic, and kept the main focus on the new Electron-based ChatGPT/Codex app. So I switched to it too. And I noticed that after restarting ChatGPT, its window didn't fill the whole available screen area anymore.
After restart, the window is still almost maximized. But not quite. There are small gaps between the window and the edges of the screen.
We are talking about something like 10 pixels here. Absolutely nothing important. The app works. The world keeps spinning. But once you notice those gaps, you start seeing them every single time you open ChatGPT.
So naturally, instead of ignoring a few pixels like a normal person, I decided to figure out what was causing it and whether it was a ChatGPT or macOS issue. Since I couldn't reproduce it with other Electron apps, ChatGPT.app looked like the more likely suspect.
Okay Codex, where is the window code?
There was one small problem with my plan: the ChatGPT app is closed source.
So my first conversation with Codex was mostly about figuring out what exactly we had to work with.
We inspected the app bundle and found app.asar, which is where Electron applications
commonly package their JavaScript code.
Great. Let's unpack it.
The production code was minified, so instead of trying to understand the entire application, I gave Codex a very specific goal: find how the main window size and position are saved and restored. I formatted the bundle, searched for window creation, followed references, and eventually found the relevant window state code.
First suspect
ChatGPT stores the window position, width, height, and whether the window was maximized. On startup, it reads that state, creates a window with the saved dimensions, and maximizes it again when necessary.
There were a few possible suspects in the window geometry code, so I tested them with Codex instead of immediately changing anything. After a few iterations, the problem started pointing back to how the window state itself was saved.
Six pixels
When ChatGPT closed, it used Electron's getNormalBounds() to save the window size.
And it did that even when the window was maximized.
I wasn't very familiar with this particular Electron API, so before changing anything I checked the documentation. And there was a pretty important detail there:
“Whatever the current state of the window (maximized, minimized or in fullscreen), this function always returns the position and size of the window in normal state.”
The documentation also says that getBounds() and getNormalBounds()
return the same rectangle only when the window is in its normal state. That made this line
much more suspicious: ChatGPT was saving the normal window bounds while the
window was maximized.
To check if this actually explained the bug, Codex helped me add some temporary logging directly into the production bundle. With the window maximized, I got this:
current:
x: 49
y: 33
width: 1463
height: 949
And at exactly the same moment:
normal:
x: 49
y: 33
width: 1457
height: 943
The window on screen was 1463×949, but ChatGPT was about to save 1457×943.
Six pixels.
We found our six pixels.
I repeated the test and got slightly different numbers, but the pattern stayed the same. The documentation explained why the values could be different, and the runtime logs confirmed that this was exactly what was happening.
One line
The existing behavior was fine for a normal window. We only needed to change what was saved when the window was maximized.
So the patch became this:
- let bounds = window.getNormalBounds()
+ let bounds = window.isMaximized() ? window.getBounds() : window.getNormalBounds()
That's it.
For a normal window, nothing changes. For a maximized window, ChatGPT now saves the bounds it actually has on screen.
The investigation was considerably longer than the fix, which is usually a good sign.
You modified ChatGPT. ChatGPT disagrees.
With the fix in place, the next step was to actually run it. I changed the production bundle,
packed everything back into app.asar, and launched my patched version of ChatGPT.
It immediately crashed.
Turns out Electron was checking the integrity of the ASAR archive. Since I had modified it, the archive hash had changed and no longer matched the one stored in the app. So I asked Codex to help update the integrity hash for my local copy and re-sign the macOS application. After that, the patched app launched normally.
Now I had ChatGPT.app and ChatGPT-Patched.app installed next to each
other, which made testing pretty straightforward. I opened the original app, maximized the
window, quit it, and launched it again. The gaps were back. Then I repeated exactly the same
steps with the patched version, and the window reopened correctly with no gaps.
I repeated the test a few times and even went back to the original app again just to make sure. Same result every time: gaps in the original, no gaps in the patched version. Perfect.
Still not fixed
After confirming the fix, I reported the bug to OpenAI. I also posted about it on X and tagged a couple of people working on ChatGPT, hoping it might help get the issue noticed.
Unfortunately, the bug is still there. So for now, my locally patched ChatGPT still handles those six pixels better than the official one.