Safari 18+ network bug - randomly - The network connection was lost

We’ve identified a recurring issue affecting our web app users on Safari 18+ (macOS and iOS). Clients have reported that some of their actions don’t go through. Initially, we couldn’t reproduce this on Chrome (Windows/Android), but after further investigation, we confirmed that the issue only occurs on Safari version 18 and above.


We tested extensively and found:

  • Safari 17.0 and 17.5 work without issues.
  • Safari 18+ (both real devices and simulators) intermittently fails to call our API.
  • The failures are random, but over a full workday can amount to 50+ missed API calls, which is highly disruptive for professional users.



We can reproduce the issue by executing a js script that calls our API repeatedly in Safari 18+. This might be related to connection keep-alive handling, but the fact that it’s isolated to Safari 18+ and never occurs on other platforms suggests a deeper compatibility problem. Safari versions handle server settings differently? We’d appreciate any insight or guidance on how to address this issue, as it’s becoming increasingly frequent with more users upgrading.


We currently only provide HTTP/1.1 and we have keep-alive with short timeout, we handle millions on requests per day, but this "connection lost" only happens on those safari versions...


It would be our server setting that is not being handled correctly within safari, but we need to know what it is that was changed between 17.5 and 18.0 and 18.5 that might cause this problem!


The network tab on developer tools shows empty for status error, ip, connection_id etc.. its like the request is being terminated very soon, or maybe the keep alive tries to reuse a connection that the server already closed...



Running this in safari console, where a testing api endpoint is called that waits around 5 seconds:


(async () => {
  for (let i = 0; i < 10; i++) {
    try {
      const res = await fetch(`https://api.redated.com/1/testes/probe`, {
        method: 'GET',
        
        headers: { 'Content-Type': 'application/json' },
        //keepalive: false
      });
      console.log(`Request ${i} ${new Date().toLocaleString()} status:`, res.status);
    } catch (err) {
      console.error(`Request ${i} ${new Date().toLocaleString()} error:`, err);
    }
    await new Promise(r => setTimeout(r, 900 - 1* Math.floor(Math.random() * 5))); // 250ms delay between requests
  }
})();


Returns a mix of requests with success and other with faillures:


< Promise {status: "pending"}
[Log] Request 0 8/7/2025, 6:54:07 PM status: – 200
[Error] The network connection was lost.
[Error] Fetch API cannot load https://api.redated.com/1/testes/probe due to access control checks.
[Error] Failed to load resource: The network connection was lost. (probe, line 0)
[Error] Request 1 8/7/2025, 6:54:08 PM error: – TypeError: Load failed
TypeError: Load failed
	Console Evaluation (Console Evaluation 14:15)
[Log] Request 2 8/7/2025, 6:54:19 PM status: – 200
[Error] The network connection was lost.
[Error] Fetch API cannot load https://api.redated.com/1/testes/probe due to access control checks.
[Error] Failed to load resource: The network connection was lost. (probe, line 0)
[Error] Request 3 8/7/2025, 6:54:20 PM error: – TypeError: Load failed
TypeError: Load failed
	Console Evaluation (Console Evaluation 14:15)
[Log] Request 4 8/7/2025, 6:54:32 PM status: – 200
[Error] The network connection was lost.
[Error] Fetch API cannot load https://api.redated.com/1/testes/probe due to access control checks.
[Error] Failed to load resource: The network connection was lost. (probe, line 0)
[Error] Request 5 8/7/2025, 6:54:33 PM error: – TypeError: Load failed
TypeError: Load failed
	Console Evaluation (Console Evaluation 14:15)
[Log] Request 6 8/7/2025, 6:54:44 PM status: – 200
[Error] The network connection was lost.
[Error] Fetch API cannot load https://api.redated.com/1/testes/probe due to access control checks.
[Error] Failed to load resource: The network connection was lost. (probe, line 0)
[Error] Request 7 8/7/2025, 6:54:45 PM error: – TypeError: Load failed
TypeError: Load failed
	Console Evaluation (Console Evaluation 14:15)
[Log] Request 8 8/7/2025, 6:54:57 PM status: – 200
[Error] The network connection was lost.
[Error] Fetch API cannot load https://api.redated.com/1/testes/probe due to access control checks.
[Error] Failed to load resource: The network connection was lost. (probe, line 0)
[Error] Request 9 8/7/2025, 6:54:58 PM error: – TypeError: Load failed
TypeError: Load failed
	Console Evaluation (Console Evaluation 14:15)


I see many other users reporting issues with network and URLSession however this is web page in safari.


Has anyone else feeling the same increase in network errors only for safari? Because we are...


Thanks.

iPhone 16

Posted on Aug 7, 2025 11:35 AM

Reply
Question marked as Top-ranking reply

Posted on Aug 12, 2025 8:37 AM

I have additional details on this issue, which I can reproduce both in Production and Local Dev, confirming it’s not a network problem, as the localhost connection never drops.



Below is the Wireshark analysis:



I will explain what this means:

Frame 10824 – 18:52:03.939197: new connection initiated (SYN, ACK, ECE).

Frame 10831 – 18:52:04.061531: Client sends payload (preflight request) to the server.

Frame 10959 – 18:52:09.207686: Server responds with data to (preflight response) to the client.

Frame 10960 – 18:52:09.207856: Client acknowledges (ACK) receipt of the preflight response.

Frame 10961 – 18:52:09.212188: Client sends the actual request payload after preflight OK and then server replies with ACK.


Frame 11092 – 18:52:14.332951: Server sends the final payload (main request response) to the client.

Frame 11093 – 18:52:14.333093: captures the client acknowledging the final server response, which marks the successful completion of the main request.


Frame 11146 – 18:52:15.348433: [IMPORTANT] the client attempts to send another new request just one second later, which is extremely close to the keep-alive timeout of 1 second. The last message from the server was at 18:52:14.332951, meaning the connection’s keep-alive timeout is predicted to end around 18:52:15.332951 but it does not. The new request is sent at 18:52:15.348433, just microseconds after the predicted timeout. The request leaves before the client browser knows the connection is closed, but by the time it arrives at the server, the connection is already dead.


Frame 11147 – 18:52:15.356910: Shows the server finally sending the FIN,ACK to indicate the connection is closed. This happens slightly later than the predicted time, at microsecond 356910 compared to the expected 332951. The FIN,ACK corresponds to sequence 1193 from the ACK of the last data packet in frame 11093.


The root cause is related to keep-alive behavior and keep-alive timeout and network timming issue with Safari reusing a closed connection without retrying. In this situation the browser should retry the request, which is what other browsers do and what Safari did before version 18, since it did not suffer from this issue. This differs from previous Safari versions and is more pronounced with HTTP/1.1 connections. When the server is configured with a short keep-alive timeout of 1 second, and requests are sent at roughly one-second intervals, such as API pings at fixed intervals or user actions like incrementing a cart quantity that trigger backend calls where the probability of failure is high.


In one test run of ten requests, five failed. The effect is even more apparent when the request uses a preflight with POST, although GET requests are also affected.


[Edited by Moderator]

Similar questions

2 replies
Question marked as Top-ranking reply

Aug 12, 2025 8:37 AM in response to MiguelQz

I have additional details on this issue, which I can reproduce both in Production and Local Dev, confirming it’s not a network problem, as the localhost connection never drops.



Below is the Wireshark analysis:



I will explain what this means:

Frame 10824 – 18:52:03.939197: new connection initiated (SYN, ACK, ECE).

Frame 10831 – 18:52:04.061531: Client sends payload (preflight request) to the server.

Frame 10959 – 18:52:09.207686: Server responds with data to (preflight response) to the client.

Frame 10960 – 18:52:09.207856: Client acknowledges (ACK) receipt of the preflight response.

Frame 10961 – 18:52:09.212188: Client sends the actual request payload after preflight OK and then server replies with ACK.


Frame 11092 – 18:52:14.332951: Server sends the final payload (main request response) to the client.

Frame 11093 – 18:52:14.333093: captures the client acknowledging the final server response, which marks the successful completion of the main request.


Frame 11146 – 18:52:15.348433: [IMPORTANT] the client attempts to send another new request just one second later, which is extremely close to the keep-alive timeout of 1 second. The last message from the server was at 18:52:14.332951, meaning the connection’s keep-alive timeout is predicted to end around 18:52:15.332951 but it does not. The new request is sent at 18:52:15.348433, just microseconds after the predicted timeout. The request leaves before the client browser knows the connection is closed, but by the time it arrives at the server, the connection is already dead.


Frame 11147 – 18:52:15.356910: Shows the server finally sending the FIN,ACK to indicate the connection is closed. This happens slightly later than the predicted time, at microsecond 356910 compared to the expected 332951. The FIN,ACK corresponds to sequence 1193 from the ACK of the last data packet in frame 11093.


The root cause is related to keep-alive behavior and keep-alive timeout and network timming issue with Safari reusing a closed connection without retrying. In this situation the browser should retry the request, which is what other browsers do and what Safari did before version 18, since it did not suffer from this issue. This differs from previous Safari versions and is more pronounced with HTTP/1.1 connections. When the server is configured with a short keep-alive timeout of 1 second, and requests are sent at roughly one-second intervals, such as API pings at fixed intervals or user actions like incrementing a cart quantity that trigger backend calls where the probability of failure is high.


In one test run of ten requests, five failed. The effect is even more apparent when the request uses a preflight with POST, although GET requests are also affected.


[Edited by Moderator]

Aug 7, 2025 3:13 PM in response to MiguelQz

Looks similar to:

Technical Q&A QA1941: Handling “The network connection was lost” Errors

and https://forum.juce.com/t/problem-with-post-requests-over-https-with-keep-alive-with-workaround/20434

and Problem With Keep-Alive on Apple Devices - Apple Community


Interesting making the request headers Content-Type': 'text/plain' instead of 'application/json' solves the issue because the request is considered "Simple" and doesn't requires an OPTION preflight!


Probably the keep-alive timeout is not being respected, safari reuses a connection way beyond the keep-alive timeout given by the server, using a dead connection, and returns "network lost" since preflight fails, then request also fails, with "access error"...


Thanks.


This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Safari 18+ network bug - randomly - The network connection was lost

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.