/errors/curl/operation-timed-out
curl: (28) Operation timed out after N milliseconds with 0 bytes received
- tool
- curl
- exit code
- 28
- versions
- curl 7.x, curl 8.x
- os
- linux, macos, windows
curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received means a time limit set with -m/--max-time (or --connect-timeout, or a libcurl default) expired before the transfer finished. curl exits with code 28 (CURLE_OPERATION_TIMEDOUT). If the message says 0 bytes received and curl -v shows Connected to, the server accepted the connection but never answered; if it fails before Connected to, packets are not getting through, usually because of a firewall.
Reproduce the error
A server on port 4881 that accepts connections and never sends anything, with a 1 second limit. The sed replaces the elapsed milliseconds, which vary slightly between runs:
node -e 'require("net").createServer(() => {}).listen(4881, "127.0.0.1"); setTimeout(() => process.exit(0), 5000)' &
sleep 1
curl -sS -m 1 http://127.0.0.1:4881/ 2>&1 | sed -E 's/after [0-9]+ milliseconds/after N milliseconds/'
echo "exit status: ${PIPESTATUS[0]}"
waitOutput
curl: (28) Operation timed out after N milliseconds with 0 bytes received exit status: 28
The two timeout options
| Option | Limits | Typical message |
|---|---|---|
| -m, --max-time SECONDS | the whole operation, connection plus transfer | Operation timed out after N milliseconds with X bytes received |
| --connect-timeout SECONDS | only the connection phase (DNS, TCP, TLS) | a connection timeout message (wording varies by version), also exit 28 |
Both accept decimals (-m 2.5). Without either option curl has no overall limit, but the connection phase still stops after curl's built-in connect timeout or the operating system's TCP timeout.
Fix by symptom
- 0 bytes received, connection succeeded: the server is stuck or slow. Check the application logs, or raise
-mif the request is legitimately slow. - Some bytes received: the transfer is slower than the limit. Raise
-m, or use--speed-limitand--speed-timeto abort only when the transfer stalls. - Fails during connect: test the port from another machine, check firewalls and security groups, and keep
--connect-timeoutshort in scripts so they fail fast.
Retries in scripts:
curl -fsS --connect-timeout 5 -m 30 --retry 3 --retry-delay 2 https://api.example.com/health--retry treats a timeout as a transient error and tries again; --retry-all-errors widens that to every error.