Skip to content

talkstream/transmission-tahoe-fix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Transmission — macOS Tahoe Fixes

Fixes for Transmission 4.1.x on macOS Tahoe 26.x (also applies to Sequoia 15.x): torrent stalls and hang on quit.

Status (June 2026)

  • Latest stable Transmission 4.1.2 (2026-06-02) contains no fix for the quit hang (tr_sessionClose() still waits unconditionally) and nothing uTP/ECN-related (verified against the 4.1.1…4.1.2 diff). The workarounds and patches here are still needed.
  • 4.1.2 does ship #8748 — a cherry-pick of #8745 (TCP segments ≥128 bytes), which closed #8308 "no downloading on Mac" — a related but distinct connectivity bug. If you see stalls on ≤4.1.1, upgrade to 4.1.2 first; the fixes here address what remains.
  • Upstream fix for the quit hang: PR #8632 — open, awaiting review (revised 2026-06-11; see Code fix).
  • #7642 (quit hang, labeled "pr welcome") — open. #8305 (slow speeds on Mac) — open.
  • Verified on macOS Tahoe 26.4 Beta 2 through 26.6.

Problems

1. Torrents stall / no download speed

Root cause (as established by local testing — see caveat below): macOS Tahoe enables ECN (net.inet.tcp.ecn_initiate_out=1) by default. Some BitTorrent peers, NAT routers, and middleboxes drop or ignore ECN-marked TCP SYN packets, causing connections to time out or cycle between brief activity and stalls.

Additionally, uTP (UDP-based transport) connections in Transmission 4.1.x die after ~2 minutes on Tahoe even with ECN disabled — disabling uTP, DHT, and UPnP/NAT-PMP is what decisively stabilizes peer connections.

Caveat: the ECN hypothesis is based on testing on one machine (disabling ECN measurably reduced stalls); it is not confirmed by Apple or Transmission upstream. The uTP/DHT/UPnP disabling (preflight Phase 1.6) was the most impactful fix in our testing.

Transmission issues: #8305, #8308

2. Hang on quit (deadlock)

Root cause: tr_sessionClose() calls closed_future.wait(), which blocks indefinitely. The session thread may be stuck in a kernel-level connect() call (exacerbated by ECN) or in disk I/O on external drives. The main thread waits forever for the session thread to signal completion.

Transmission issues: #7642 (pr welcome), #7784, #4759, #6654

Solution

OS-level workarounds (scripts/)

Script Purpose
transmission-preflight.sh Apply all OS fixes before launching Transmission
transmission-enhanced-monitor.sh Real-time monitoring with quit-hang detection and auto-spindump
transmission-safe-quit.sh Safe quit: pause torrents → drain connections → quit → SIGTERM/SIGKILL fallback
com.local.disable-ecn.plist LaunchDaemon to persist the ECN fix across reboots

Quick start:

# Apply fixes (requires sudo for sysctl/pmset)
sudo bash scripts/transmission-preflight.sh

# Install persistent ECN fix
sudo cp scripts/com.local.disable-ecn.plist /Library/LaunchDaemons/
sudo launchctl bootstrap system /Library/LaunchDaemons/com.local.disable-ecn.plist

# Monitor Transmission (sudo recommended: spindump needs root)
sudo bash scripts/transmission-enhanced-monitor.sh 3

# Safe quit when needed
bash scripts/transmission-safe-quit.sh

Optional: if you download to an external drive, export TORRENT_VOLUME=<VolumeName> (the name under /Volumes/) — the preflight will warn when the volume is missing, and the monitor will report per-volume disk I/O.

The monitor writes its log and spindumps to a private per-user directory: $TMPDIR/transmission-samples-<uid>/ (the exact paths are printed at startup).

Code fix (patches/)

Patch Target
0001-fix-quit-hang-add-timeout-to-session-shutdown.patch upstream main — identical to PR #8632
0002-backport-quit-hang-timeout-4.1.2.patch the 4.1.2 stable release tag

Replaces closed_future.wait() with closed_future.wait_for(timeout + 5s) in tr_sessionClose(). If the session thread does not complete within the window, a warning is logged and the function returns without freeing the session or the promise — the stuck session thread may still touch both, so freeing them would be a use-after-free. They are intentionally leaked; the process is exiting anyway. The promise is heap-allocated so it can outlive the function's stack frame on that path. The normal quit path is unchanged.

git clone https://github.com/transmission/transmission.git
cd transmission && git checkout 4.1.2
git apply /path/to/patches/0002-backport-quit-hang-timeout-4.1.2.patch

Both patches are compile-verified (libtransmission target, clang, macOS arm64).

Fixes applied by the preflight script

Fix Setting Default Fixed Persistent
Disable ECN net.inet.tcp.ecn_initiate_out + net.inet.tcp.ecn 1 0 Via LaunchDaemon
Disable disk sleep pmset disksleep 10 0 No (reboot resets)
Disable App Nap NSAppSleepDisabled not set YES Yes
Reduce peers PeersTorrent/PeersTotal 120/400 60/200 Yes
Reduce TCP connect timeout net.inet.tcp.keepinit 75000ms 10000ms No (reboot resets)
Disable uTP UTPGlobal YES NO Yes
Disable DHT DHTGlobal YES NO Yes
Disable UPnP/NAT-PMP NatTraversal YES NO Yes

All defaults write org.m0k.transmission settings persist across reboots; sysctl/pmset values reset on reboot (hence the LaunchDaemon for ECN, or re-run the preflight).

Tested environment

  • macOS Tahoe 26.4 Beta 2 → 26.6, Apple silicon
  • Transmission 4.1.1 (build 56442e2929)
  • Downloads to an external Thunderbolt SSD (APFS)

License

Scripts: MIT (see LICENSE). Patches under patches/ are derived from Transmission and follow its license (GPL-2.0-or-later).

About

Fixes for Transmission 4.x quit-hang and ECN/uTP stalls on macOS Tahoe 26.x

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages