Resolved | How to avoid Photoshop plugin not quitting after an export

I’m running the last version of Topaz Photo i.e. 1.4.0 as a Photoshop 2024 plugin. After the export, the plugin window closes but the icon in the dock stays and the process is still there. I have to force kill it each time.

This is a new issue, just after install and on 2 brand new Mac Silicon machines running Tahoe 26.4.

I found why by asking Claude Code to analyze the log files because it worked once. So it did a comparison.

The root cause was that my LittleSnitch firewall was blocking Internet access to the plugin.
This is not the first time I noticed that network or file access permissions can cause a strange behavior without any message to report it.

Anyhow, here is Claude Code analysis:

Environment

  • macOS Darwin 25.4.0, Topaz Photo 1.4.0, Photoshop plugin mode
  • Little Snitch blocking outbound network from the plugin process

Symptom

After applying and exporting an image back to Photoshop, the plugin occasionally hangs instead of quitting. Photoshop waits indefinitely for the plugin to exit. The only recovery is force-quitting and relaunching.

Reproduction

Intermittent. Observed once out of two back-to-back sessions on 2026-04-01. Both sessions had identical network conditions (all outbound blocked by Little Snitch).

Root cause analysis

When the plugin starts, it fires ~15 network requests concurrently (auth token refresh, product info fetches, Amplitude analytics, update check, cloud feature flags, pricing modal assets). With outbound network blocked,
all of these hang for ~30 seconds before the app’s internal timeout cancels them in bulk.

This creates a flood of QNetworkReply error callbacks dispatched on the main thread (1f807d8c0), all at once:

  • ~15 OperationCanceledError with associated FetchProductInfo failure handlers
  • ~10 UnknownNetworkError / “Socket is not connected” follow-up errors
  • Amplitude request error handlers
  • Auth fallback to cached credentials

The bug is a timing collision. The IPC quit signal from Photoshop arrives via the local Unix socket and is processed on the same main-thread Qt event loop. If the export completes at the wrong moment — just as the
30-second network timeout fires — the quit signal gets buried under or preempted by the network error callback flood.

Evidence from logs

Failed session (08:55:59):

┌─────────────────────────────┬──────────────────────────────────────────────────────────────────┐
│ Time │ Event │
├─────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ 08:56:20.757 │ [EXPORT] All images exported — export done, plugin should exit │
├─────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ 08:56:20.757 → 08:56:29.497 │ ~9 second gap — no “Exiting app”, main thread unresponsive │
├─────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ 08:56:29.497 │ 30s network timeout fires, ~40 error callbacks flood main thread │
├─────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ 08:56:34.498 │ Log ends — no shutdown sequence, process killed externally │
└─────────────────────────────┴──────────────────────────────────────────────────────────────────┘

Successful session (08:57:41):

┌──────────────┬────────────────────────────────────────────────────────────────────────────────────┐
│ Time │ Event │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────┤
│ 08:58:12.500 │ 30s network timeout fires, error callbacks processed │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────┤
│ 08:58:19.299 │ [EXPORT] All images exported — export done 7 seconds after network errors resolved │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────┤
│ 08:58:19.309 │ Exiting app: 0 — 10ms later, clean shutdown │
└──────────────┴────────────────────────────────────────────────────────────────────────────────────┘

The only difference: in the successful session, the network error cascade had already completed 7 seconds before export, so the event loop was clear when the quit signal arrived.

Suggested fixes

  1. Process the IPC quit signal with higher priority than network reply callbacks, or handle it on a dedicated thread rather than the main Qt event loop.
    ✻ Sautéed for 32setwork requests synchronously on the main thread. Move auth refresh, product info, and analytics to a background QThread so their failure handlers can’t starve the event loop.
  2. Add a quit timeout/retry — if the plugin doesn’t exit within N seconds after export, poll the IPC channel again for the quit command.