Skip to main content

Command Palette

Search for a command to run...

When macOS 26 (Tahoe) Blocked Python Socket Connections — and How LaunchDaemon Fixed It

Published
3 min read

When macOS 26 (Tahoe) Blocked Python Socket Connections — and How LaunchDaemon Fixed It

TL;DR

On macOS 26 (Tahoe), WebSocket connections from Homebrew-installed Python were failing with errno 65 (No route to host). curl worked fine, but Python kept failing. The culprit: TCC (Transparency, Consent, and Control). The fix: switching from LaunchAgent to LaunchDaemon.


Background

We were building an automated setup script to install OpenClaw (an AI assistant framework) on refurbished Mac minis (M1, macOS 26.0.1 Tahoe) for resale. A Python script running as a LINE Bridge — connecting to a WebSocket relay server — was registered as a LaunchAgent, but the Gateway refused to start.

The logs showed:

socket.connect_ex(('192.168.x.x', 3500)) → errno 65: No route to host

The target was another host on the same LAN. Ping worked. curl worked. But Python failed consistently.


Debugging

Everything We Checked First (All Wrong)

1. IP/Port problem?

ping 192.168.x.x        # OK
curl http://192.168.x.x:3500  # OK
nc -zv 192.168.x.x 3500       # OK

All passed. The problem was isolated to Python.

2. Hairpin NAT?

We were initially connecting to an external domain (wss://linebot.techsfree.com). Some routers block connections from inside the LAN to the router's own external IP (no hairpin NAT support). That was a real issue — we switched to the internal IP — but the error persisted.

3. Firewall?

sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
# Firewall is disabled.

Nope.

The Real Culprit: TCC

Running sudo python3 script.py directly worked. Running via LaunchAgent (user-level) failed. Root succeeded.

macOS TCC (Transparency, Consent, and Control) manages third-party app access to system resources. On macOS 26 Tahoe, Homebrew-installed Python became subject to TCC checks for network connections when launched from user-space (LaunchAgent).

Verification:

# Via LaunchAgent (user-level) → FAIL
launchctl load ~/Library/LaunchAgents/com.openclaw.linebridge.plist
# → errno 65: No route to host

# Direct sudo execution → OK
sudo /opt/homebrew/bin/python3 line_bridge_v2.py
# → Connected to relay server ✓

# subprocess.run(['curl', ...]) → OK
# curl is a system binary and bypasses TCC

The Fix: Promote to LaunchDaemon

LaunchAgents (~/Library/LaunchAgents/) run in user space. LaunchDaemons (/Library/LaunchDaemons/) run at the system level (root) and bypass TCC.

Before (LaunchAgent):

<!-- ~/Library/LaunchAgents/com.openclaw.linebridge.plist -->
<key>Label</key>
<string>com.openclaw.linebridge</string>

After (LaunchDaemon):

<!-- /Library/LaunchDaemons/com.openclaw.linebridge.plist -->
<key>Label</key>
<string>com.openclaw.linebridge</string>
<key>UserName</key>
<string>openclaw</string>  <!-- Runs as system daemon but with user file access -->

The UserName key lets you run as a root-level daemon while still reading/writing files as the openclaw user.

# Register
sudo launchctl bootstrap system /Library/LaunchDaemons/com.openclaw.linebridge.plist
sudo launchctl enable system/com.openclaw.linebridge

Result: Connected to relay server ✓ — fixed immediately.


macOS 26 TCC Summary

Execution methodTCC restrictedNotes
System binaries (curl, etc.)NoAlways works
sudo python3NoRoot bypasses TCC
LaunchAgent + Homebrew PythonYeserrno 65
LaunchDaemon + UserName keyNo✅ Recommended
subprocess.run(['curl', ...])NoWorkaround via system binary

macOS 26 has significantly tightened security. Scripts that worked fine on earlier versions may break — especially resident daemons + third-party runtimes + network connections.


Side Note: Mac Mini Factory Automation

This issue appeared while building a product: refurbished Mac minis pre-installed with OpenClaw, sold as AI assistants.

Unlike GMK Ubuntu units (where Clonezilla image cloning works), Apple Silicon + SIP makes Mac imaging impossible. Instead, we built a set of automation scripts:

  • factory-setup-mac.sh — Full automated install (~15 min)
  • per-unit-setup-mac.sh — Per-unit token assignment (5 sec)
  • factory-qc-mac.sh — Pre-ship QC (22-item checklist)
  • factory-clean-mac.sh — Pre-ship cleanup

The TCC fix is now built into factory-setup-mac.sh — future units will automatically register the LINE Bridge as a LaunchDaemon.

More from this blog

A

techsfree

208 posts