curl exit codes: 6, 7, 22, 28, 35, 56, 60 and the rest
- tool
- curl
- versions
- curl 7.x, curl 8.x
- os
- linux, macos, windows
curl's exit code tells a script why a transfer failed: 0 means success, and every other value maps to a libcurl error such as 6 (could not resolve the host), 7 (could not connect), 22 (HTTP status 400 or above, only with -f) or 28 (timeout). The number is also printed in the error message, curl: (7) .... With -sS, curl hides the progress meter but still prints that message to stderr.
Common exit codes
| Code | libcurl name | Meaning | Typical cause |
|---|---|---|---|
| 0 | CURLE_OK | Success | The transfer completed (HTTP errors too, unless -f is used) |
| 1 | CURLE_UNSUPPORTED_PROTOCOL | Unsupported protocol | Typo in the scheme (htp://) or a protocol not built in |
| 3 | CURLE_URL_MALFORMAT | Malformed URL | Spaces or invalid characters in the URL |
| 5 | CURLE_COULDNT_RESOLVE_PROXY | Could not resolve proxy | Wrong host in http_proxy / https_proxy |
| 6 | CURLE_COULDNT_RESOLVE_HOST | Could not resolve host | Typo in the host name, no DNS, offline |
| 7 | CURLE_COULDNT_CONNECT | Failed to connect | Nothing listening on the port, firewall reject |
| 18 | CURLE_PARTIAL_FILE | Partial file | Connection closed before the announced size arrived |
| 22 | CURLE_HTTP_RETURNED_ERROR | HTTP error | Status 400 or above with -f / --fail |
| 23 | CURLE_WRITE_ERROR | Write error | Output directory missing, disk full, closed pipe |
| 26 | CURLE_READ_ERROR | Read error | File given to -T or -d @file cannot be read |
| 28 | CURLE_OPERATION_TIMEDOUT | Timeout | --max-time or --connect-timeout reached |
| 35 | CURLE_SSL_CONNECT_ERROR | TLS handshake failed | Protocol or cipher mismatch, plain HTTP on a TLS port |
| 47 | CURLE_TOO_MANY_REDIRECTS | Too many redirects | Redirect loop with -L (limit set by --max-redirs) |
| 52 | CURLE_GOT_NOTHING | Empty reply from server | Server closed the connection without answering |
| 56 | CURLE_RECV_ERROR | Receive failure | Connection reset while reading the response |
| 60 | CURLE_PEER_FAILED_VERIFICATION | Certificate problem | Self-signed, expired or wrong-host certificate |
The full list, more than 90 codes, is in the libcurl error documentation. Codes that are no longer used stay reserved, so the numbers never change meaning.
Seen in practice
Each command below fails in a different way against local addresses (ports 4303 and 4304) or with a malformed URL:
node -e 'require("http").createServer((q, r) => { if (q.url === "/slow") setTimeout(() => r.end("late\n"), 2500); else { r.statusCode = 500; r.end("error\n"); } }).listen(4303, "127.0.0.1"); setTimeout(() => process.exit(0), 5000)' &
sleep 1
run() { curl -sS "$@" 2>&1 | sed -E 's/[0-9]+ (ms|milliseconds)/N \1/'; echo " -> exit ${PIPESTATUS[0]}"; }
run htp://127.0.0.1:4303/
run 'http://exa mple.com/'
run http://127.0.0.1:4304/
run -o /dev/null -f http://127.0.0.1:4303/
run -o /dev/null --max-time 1 http://127.0.0.1:4303/slow
waitOutput
curl: (1) Protocol "htp" not supported -> exit 1 curl: (3) URL rejected: Malformed input to a URL function -> exit 3 curl: (7) Failed to connect to 127.0.0.1:4304 after N ms: Could not connect to server -> exit 7 curl: (22) The requested URL returned error: 500 -> exit 22 curl: (28) Operation timed out after N milliseconds with 0 bytes received -> exit 28
Using the code in a script
curl -fsS --max-time 10 -o data.json https://api.example.org/data
case $? in
0) echo "ok" ;;
6) echo "DNS problem" ;;
7) echo "service down" ;;
22) echo "HTTP error" ;;
28) echo "timed out" ;;
*) echo "other curl error" ;;
esaccurl -w '%{exitcode}' (curl 7.75.0 and later) prints the same number from inside the write-out format.