Short answer
Check the server log for the request first: a crash, a timeout or a request size limit closes the connection without a response. If it fails only now and then, the server is closing idle keep-alive connections: retry the request once with RetryClient, and make sure the URL scheme matches the port (http vs https). For local servers on the emulator, use 10.0.2.2.
Why the connection closes early, and the fix
01
The server crashed or timed out on this request
A server that throws, runs out of memory, or hits a proxy or load balancer timeout can close the socket without answering. The server or proxy log for that time shows the real error; fix it there. Large uploads can also hit a body size limit (for example nginx client_max_body_size).
02
A reused keep-alive connection the server already closed
“Gets and sets the idle timeout of non-active persistent (keep-alive) connections. The default value is 15 seconds.” Dart, HttpClient.idleTimeout
Dart keeps connections open for reuse. If the server closes idle connections sooner than the client stops reusing them, the next request on that connection fails at random. Retry safe requests once, and lower the client idle timeout below the server’s by passing your own HttpClient through IOClient (mobile and desktop; dart:io isn’t available on the web).
import 'dart:io'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; import 'package:http/retry.dart'; final inner = HttpClient()..idleTimeout = const Duration(seconds: 5); final client = RetryClient( IOClient(inner), retries: 2, whenError: (error, _) => error is http.ClientException, );03
Retrying without a plan
“package:http/retry.dart provides a class RetryClient to wrap an underlying http.Client which transparently retries failing requests.” pub.dev, package:http
RetryClient only retries on a 503 response by default, so connection errors need whenError. Retry only requests that are safe to repeat, such as GET, or POSTs your server deduplicates.
04
http sent to an https port, or the wrong host
Plain http to a port that expects TLS (or the reverse) makes the server drop the connection. Check the scheme and port, and on the Android emulator call your computer at 10.0.2.2, not localhost.
Checked against the vendor’s docs on : Dart API: HttpClient.idleTimeout; pub.dev: package:http (Client, RetryClient).
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
Related: Flutter “SocketException: Connection refused” · Flutter “SocketException: Failed host lookup” · Flutter “HandshakeException: CERTIFICATE_VERIFY_FAILED” · Flutter “type 'Null' is not a subtype of type 'String'”