Reliable HTTP automation depends on failing fast when servers respond with HTTP errors instead of treating them as successful calls. Shell scripts, CI pipelines, and health checks frequently rely on cURL to invoke APIs, yet the default behavior happily accepts many 4xx and 5xx responses as success as long as the transfer itself completes.

The cURL executable reports problems through numeric exit codes while streaming the HTTP response body and headers to standard output and standard error. Without additional options, only transport or protocol failures such as DNS errors, TLS negotiation problems, and malformed responses change the exit code, while application-level HTTP status codes such as 404 or 500 leave it at 0.

The --fail and --fail-with-body flags adjust this behavior by mapping HTTP 4xx and 5xx responses to dedicated error codes that integrate cleanly with shell conditionals on Linux. Combining these flags with --silent and --show-error keeps logs concise and makes failures easy to detect, but discarding response bodies on error can hide diagnostics, so the chosen options should reflect debugging needs and how downstream consumers parse output.

Steps to fail on HTTP errors with cURL:

  1. Run a cURL request against a known 404 endpoint to inspect the HTTP status and body without failure handling.
    $ curl -i https://httpbin.org/status/404
    HTTP/1.1 404 NOT FOUND
    Date: Mon, 13 May 2024 10:15:01 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 0
    Connection: keep-alive
    Server: gunicorn/19.9.0
    ##### snipped #####

    The presence of an HTTP status line with 404 and an HTML body shows that the server returned an application-level error even though the transfer itself completed successfully.

  2. Print the exit status of the previous command to confirm that cURL treated the 404 response as success.
    $ echo $?
    0

    An exit status of 0 indicates that only network and protocol errors are considered failures by default, not the HTTP status code.

  3. Repeat the request with --fail, --silent, and --show-error to convert HTTP 4xx and 5xx responses into formatted errors.
    $ curl --fail --silent --show-error https://httpbin.org/status/404
    curl: (22) The requested URL returned error: 404 NOT FOUND

    With --fail enabled, cURL stops writing the response body when a 4xx or 5xx status is encountered, which can break consumers that expect JSON or HTML error payloads for diagnostics.

  4. Print the exit status again to verify that cURL now signals an HTTP error with a non-zero code.
    $ echo $?
    22

    Error code 22 is the specific cURL status for an HTTP response that triggered --fail, making it straightforward to test in shell scripts.

  5. Use the --fail-with-body option to keep the response body while still failing on HTTP errors for improved diagnostics.
    $ curl --fail-with-body --silent https://httpbin.org/status/404
    <html>
    <head><title>404 Not Found</title></head>
    ##### snipped #####
    $ echo $?
    22
    $ curl --fail-with-body --silent https://httpbin.org/status/200
    {
      "message": "ok"
    }
    $ echo $?
    0

    Success signals: failing URLs return a non-zero exit status while preserving the error payload for logging, and successful URLs return both the expected body and exit status 0, allowing scripts and CI jobs to branch cleanly on cURL return codes.

  6. Integrate the flags into a small shell script so that automation can stop immediately when cURL returns a failing exit status.
    $ cat check_endpoint.sh
    #!/usr/bin/env bash
    set -euo pipefail
    
    URL="https://httpbin.org/status/404"
    
    curl --fail-with-body --silent --show-error "$URL"
    echo "Request succeeded"
    
    $ bash check_endpoint.sh
    curl: (22) The requested URL returned error: 404 NOT FOUND

    Using --fail or --fail-with-body with strict shell options causes the script to exit as soon as the HTTP call fails, preventing later steps from running against an unhealthy dependency.

Discuss the article:

Comment anonymously. Login not required.