Network.framework Diagnostics
Overview
Core principle 85% of networking problems stem from misunderstanding connection states, not handling network transitions, or improper error handlingβnot Network.framework defects.
Network.framework is battle-tested in every iOS app (powers URLSession internally), handles trillions of requests daily, and provides smart connection establishment with Happy Eyeballs, proxy evaluation, and WiFi Assist. If your connection is failing, timing out, or behaving unexpectedly, the issue is almost always in how you're using the framework, not the framework itself.
This skill provides systematic diagnostics to identify root causes in minutes, not hours.
Red Flags β Suspect Networking Issue
If you see ANY of these, suspect a networking misconfiguration, not framework breakage:
-
Connection times out after 60 seconds with no clear error
-
TLS handshake fails with "certificate invalid" on some networks
-
Data sent but never arrives at receiver
-
Connection drops when switching WiFi to cellular
-
Works perfectly on WiFi but fails 100% of time on cellular
-
Works in simulator but fails on real device
-
Connection succeeds on your network but fails for users
-
β FORBIDDEN "Network.framework is broken, we should rewrite with sockets"
- Network.framework powers URLSession, used in every iOS app
- Handles edge cases you'll spend months discovering with sockets
- Apple engineers have 10+ years of production debugging baked into framework
- Switching to sockets will expose you to 100+ edge cases
Critical distinction Simulator uses macOS networking stack (not iOS), hides cellular-specific issues (IPv6-only networks), and doesn't simulate network transitions. MANDATORY: Test on real device with real network conditions.
Mandatory First Steps
ALWAYS run these commands FIRST (before changing code):
connection.stateUpdateHandler = { state in
print("\(Date()): Connection state: \(state)")
}
print("TLS version: \(tlsParameters.minimumTLSProtocolVersion)")
print("Cipher suites: \(tlsParameters.tlsCipherSuites ?? [])")
What this tells you
| Observation |
Diagnosis |
Next Step |
| Stuck in .preparing > 5 seconds |
DNS failure or network down |
Pattern 1a |
| Moves to .waiting immediately |
No connectivity (Airplane Mode, no signal) |
Pattern 1b |
| .failed with POSIX error 61 |
Connection refused (server not listening) |
Pattern 1c |
| .failed with POSIX error 50 |
Network down (interface disabled) |
Pattern 1d |
| .ready then immediate .failed |
TLS handshake failure |
Pattern 2b |
| .ready, send succeeds, no data arrives |
Framing problem or receiver not processing |
Pattern 3a |
| Works WiFi, fails cellular |
IPv6-only network (hardcoded IPv4) |
Pattern 5a |
| Works without VPN, fails with VPN |
Proxy interference or DNS override |
Pattern 5b |
MANDATORY INTERPRETATION
Before changing ANY code, identify ONE of these:
- If stuck in .preparing AND network is available β DNS failure (check nslookup)
- If .waiting immediately AND Airplane Mode is off β Interface-specific issue (cellular blocked)
- If .failed POSIX 61 β Server issue (check server logs)
- If .failed with TLS error -9806 β Certificate validation (check with openssl)
- If .ready but data not arriving β Framing or receiver issue (enable packet capture)
If diagnostics are contradictory or unclear
- STOP. Do NOT proceed to patterns yet
- Add timestamp logging to every send/receive call
- Enable packet capture (Charles/Wireshark)
- Test on different device to isolate hardware vs software issue
Decision Tree
Use this to reach the correct diagnostic pattern in 2 minutes:
Network problem?
ββ Connection never reaches .ready?
β ββ Stuck in .preparing for >5 seconds?
β β ββ DNS lookup timing out? β Pattern 1a (DNS Failure)
β β ββ Network available but can't reach host? β Pattern 1c (Connection Refused)
β β ββ First connection slow, subsequent fast? β Pattern 1e (DNS Caching)
β β
β ββ Moves to .waiting immediately?
β β ββ Airplane Mode or no signal? β Pattern 1b (No Connectivity)
β β ββ Cellular blocked by parameters? β Pattern 1b (Interface Restrictions)
β β ββ VPN connecting? β Wait and retry
β β
β ββ .failed with POSIX error 61?
β β ββ β Pattern 1c (Connection Refused)
β β
β ββ .failed with POSIX error 50?
β ββ β Pattern 1d (Network Down)
β
ββ Connection reaches .ready, then fails?
β ββ Fails immediately after .ready?
β β ββ TLS error -9806? β Pattern 2b (Certificate Validation)
β β ββ TLS error -9801? β Pattern 2b (Protocol Version)
β β ββ POSIX error 54? β Pattern 2d (Connection Reset)
β β
β ββ Fails after network change (WiFi β cellular)?
β β ββ No viabilityUpdateHandler? β Pattern 2a (Viability Not Handled)
β β ββ Didn't detect better path? β Pattern 2a (Better Path)
β β ββ IPv6 β IPv4 transition? β Pattern 5a (Dual Stack)
β β
β ββ Fails after timeout?
β β ββ β Pattern 2c (Receiver Not Responding)
β β
β ββ Random disconnects?
β ββ β Pattern 2d (Network Instability)
β
ββ Data not arriving?
β ββ Send succeeds, receive never returns?
β β ββ No message framing? β Pattern 3a (Framing Problem)
β β ββ Wrong byte count? β Pattern 3b (Min/Max Bytes)
β β ββ Receiver not calling receive()? β Check receiver code
β β
β ββ Partial data arrives?
β β ββ receive(exactly:) too large? β Pattern 3b (Chunking)
β β ββ Sender closing too early? β Check sender lifecycle
β β ββ Buffer overflow? β Pattern 3b (Buffer Management)
β β
β ββ Data corrupted?
β β ββ TLS disabled? β Pattern 3c (No Encryption)
β β ββ Binary vs text encoding? β Check ContentType
β β ββ Byte order (endianness)? β Use network byte order
β β
β ββ Works sometimes, fails intermittently?
β ββ β Pattern 3d (Race Condition)
β
ββ Performance degrading?
β ββ Latency increasing over time?
β β ββ TCP congestion? β Pattern 4a (Congestion Control)
β β ββ No contentProcessed pacing? β Pattern 4a (Buffering)
β β ββ Server overloaded? β Check server metrics
β β
β ββ Throughput decreasing?
β β ββ Network transition WiFi β cellular? β Pattern 4b (Bandwidth Change)
β β ββ Packet loss increasing? β Pattern 4b (Network Quality)
β β ββ Multiple streams competing? β Pattern 4b (Prioritization)
β β
β ββ High CPU usage?
β β ββ Not using batch for UDP? β Pattern 4c (Batching)
β β ββ Too many small sends? β Pattern 4c (Coalescing)
β β ββ Using sockets instead of Network.framework? β Migrate (30% CPU savings)
β β
β ββ Memory growing?
β ββ Not releasing connections? β Pattern 4d (Connection Leaks)
β ββ Not cancelling on deinit? β Pattern 4d (Lifecycle)
β ββ Missing [weak self]? β Pattern 4d (Retain Cycles)
β
ββ Works on WiFi, fails on cellular/VPN?
ββ IPv6-only cellular network?
β ββ Hardcoded IPv4 address? β Pattern 5a (IPv4 Literal)
β ββ getaddrinfo with AF_INET only? β Pattern 5a (Address Family)
β ββ Works on some carriers, not others? β Pattern 5a (Regional IPv6)
β
ββ Corporate VPN active?
β ββ Proxy configuration failing? β Pattern 5b (PAC)
β ββ DNS override blocking hostname? β Pattern 5b (DNS)
β ββ Certificate pinning failing? β Pattern 5b (TLS in VPN)
β
ββ Port blocked by firewall?
β ββ Non-standard port? β Pattern 5c (Firewall)
β ββ Outbound only? β Pattern 5c (NATing)
β ββ Works on port 443, not 8080? β Pattern 5c (Port Scanning)
β
ββ Peer-to-peer connection failing?
β ββ NAT traversal issue? β Pattern 5d (STUN/TURN)
β ββ Symmetric NAT? β Pattern 5d (NAT Type)
β ββ Local network only? β Pattern 5d (Bonjour/mDNS)
β
ββ URLSession fails but NWConnection works?
ββ HTTP URL blocked? β Pattern 6a (ATS HTTP Block)
ββ "SSL error" on HTTPS? β Pattern 6b (ATS TLS Version)
ββ Works on older iOS? β Pattern 6a/6b (ATS enforcement)
Pattern Selection Rules (MANDATORY)
Before proceeding to a pattern:
- Connection never reaching .ready β Start with Pattern 1 (DNS, connectivity, refused)
- TLS error codes β Jump directly to Pattern 2b (Certificate validation)
- Data not arriving β Enable packet capture FIRST, then Pattern 3
- Network-specific (works WiFi, fails cellular) β Test on that exact network, Pattern 5
- Performance degradation β Profile with Instruments Network template, Pattern 4
Apply ONE pattern at a time
- Implement the fix from one pattern
- Test thoroughly
- Only if issue persists, try next pattern
- DO NOT apply multiple patterns simultaneously (can't isolate cause)
FORBIDDEN
- Guessing at solutions without diagnostics
- Changing multiple things at once
- Assuming "just needs more timeout"
- Disabling TLS "temporarily"
- Switching to sockets to "avoid framework issues"
Diagnostic Patterns
Pattern 1a: DNS Resolution Failure
Time cost 10-15 minutes
Symptom
- Connection stuck in .preparing for >5 seconds
- Eventually fails or times out
- Works with IP address but not hostname
- Works on one network, fails on another
Diagnosis
Common causes
- DNS server unreachable (corporate network blocks external DNS)
- Hostname typo or doesn't exist
- DNS caching stale entry (rare, but happens)
- VPN blocking DNS resolution
Fix
let connection = NWConnection(
host: NWEndpoint.Host("correct-hostname.com"),
port: 443,
using: .tls
)
Verification
- Run
nslookup your-hostname.com β should return IP in <1 second
- Test on cellular (different DNS servers) β should work
- Check corporate network DNS configuration
Prevention
- Use well-known hostnames (don't rely on internal DNS)
- Test on multiple networks during development
- Don't hardcode IPs (if DNS fails, you need to fix DNS, not bypass it)
Pattern 2b: TLS Certificate Validation Failure
Time cost 15-20 minutes
Symptom
- Connection reaches .ready briefly, then .failed immediately
- Error:
-9806 (kSSLPeerCertInvalid)
- Error:
-9807 (kSSLPeerCertExpired)
- Error:
-9801 (kSSLProtocol)
- Works on some servers, fails on others
Diagnosis
openssl s_client -connect example.com:443 -showcerts
openssl s_client -connect example.com:443 | openssl x509 -noout -dates
openssl s_client -connect example.com:443 -showcerts | grep "CN="
Common causes
- Self-signed certificate (dev/staging servers)
- Expired certificate
- Certificate hostname mismatch (cert for "example.com" but connecting to "www.example