cURL setup and cURL transfer errors occur at different stages. In PHP 8 and later, an invalid option identifier causes curl_setopt() or curl_setopt_array() to throw ValueError. A supported option can still return false when its value cannot be applied, while curl_exec() reports transfer failure.
Last updated: October 11, 2026.
<?php
declare(strict_types=1);
$curl = curl_init('https://api.example.com/status');
try {
$configured = curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
]);
if (!$configured) {
throw new RuntimeException('A cURL option could not be applied.');
}
$body = curl_exec($curl);
if ($body === false) {
throw new RuntimeException(curl_error($curl), curl_errno($curl));
}
} catch (ValueError $error) {
throw new InvalidArgumentException('Unsupported cURL option.', 0, $error);
} finally {
curl_close($curl);
}Use a fixed option list controlled by the application. Do not accept raw option numbers or arbitrary callback names from a request. Add HTTP status checks with curl_getinfo() because an HTTP 404 or 500 response is usually a completed transfer, not a cURL transport failure.
Distinguish configuration errors from network errors
The PHP curl_setopt() documentation states that the function returns true or false and throws ValueError when the option identifier is invalid. The changelog records this exception behavior beginning with PHP 8.0. Code migrated from PHP 7 may have expected only a warning or false result.
An option constant can also depend on the installed PHP and libcurl versions. Check defined() before using an optional constant in a reusable library, or establish a minimum runtime version and fail during application startup.
Preserve useful diagnostics without leaking secrets
After curl_exec() returns false, capture curl_errno() and curl_error() before closing the handle. Log the operation name, destination host, elapsed time, and numeric error, but redact authorization headers, cookies, query tokens, and request bodies.
Set both connection and total timeouts so a worker cannot wait indefinitely. Apply retries only to operations known to be safe or protected by idempotency. Continue with safe HTTP logging, PHP socket timeouts, and preventing duplicate API operations.