Skip to content

Potential regression from 8.17.0 onwards regarding CURLOPT_ERRORBUFFER #20608

@TibiIius

Description

@TibiIius

I did this

We noticed the following behavior during our test cases using libcurl:

We use libcurl to make a request against a local HTTP server using a self-signed cert.
libcurl does not know about this certificate, so we expect a CURLE_PEER_FAILED_VERIFICATION upon running curl_easy_perform(). This works as intended. However, we also read the contents inside of curl's error buffer and display that as well. Since curl 8.17.0, the most recent error message stored within the buffer is failed to open socket: Address family not supported by protocol instead of SSL certificate problem: self-signed certificate.

We only noticed this behavior on our Linux machines (we also tested macOS and Windows), though I don't know if this is just a side-effect of OS-specifics or configuration.

I am unsure as to whether this is to be expected though, which is why I wrote "potential regression". Feel free to close the issue if this is expected behavior. If so, I'd guess we are meant to just always use curl_easy_strerror(CURL_error_code) instead, or is there something I'm missing here?

Reproducible example:

#include <memory>

extern "C" {
#include <curl/curl.h>
}

namespace playground {
class CurlHelper {
public:
  explicit CurlHelper();

  auto perform(const std::string &url) -> long;

private:
  std::array<char, CURL_ERROR_SIZE> errorBuffer;

  auto checkCurlError(CURLcode res, const std::string &url) -> void;
  auto checkPointer() -> void const;

  std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> curl;
};
} // namespace playground

#include "openssl/crypto.h"
#include "openssl/ssl.h"
#include <iostream>
#include <memory>
#include <sstream>
#include <string>

namespace playground {
CurlHelper::CurlHelper() : curl(curl_easy_init(), curl_easy_cleanup), errorBuffer() {
  if (!curl) {
    throw std::runtime_error("Failed to initialize CURL");
  }

  curl_easy_setopt(this->curl.get(), CURLOPT_ERRORBUFFER, this->errorBuffer.data());
}

auto CurlHelper::checkCurlError(CURLcode res, const std::string &url) -> void {
  if (res != CURLE_OK) {
    std::stringstream ss;
    ss << "CURL error: ";

    if (this->errorBuffer.empty()) {
      ss << curl_easy_strerror(res);
    } else {
      ss << this->errorBuffer.data();
    }

    ss << " for URL: " << url << " (CURLcode: " << res << ")" << std::endl;
    throw std::runtime_error(ss.str());
  }
}

auto CurlHelper::checkPointer() -> void const {
  if (!this->curl) {
    throw std::runtime_error("CURL pointer is null");
  }
}

auto CurlHelper::perform(const std::string &url) -> long {
  this->checkPointer();

  curl_easy_setopt(this->curl.get(), CURLOPT_URL, url.c_str());
  curl_easy_setopt(this->curl.get(), CURLOPT_SSL_VERIFYHOST, true);
  curl_easy_setopt(this->curl.get(), CURLOPT_SSL_VERIFYPEER, true);

  std::cout << "Performing CURL request to URL: " << url << std::endl;

  auto res = curl_easy_perform(this->curl.get());

  this->checkCurlError(res, url);

  long statusCode;
  curl_easy_getinfo(this->curl.get(), CURLINFO_RESPONSE_CODE, &statusCode);
  return statusCode;
}
} // namespace playground

int main(int argc, char** argv) {
  auto helper = std::make_unique<playground::CurlHelper>();

  std::cout << helper->perform("https://localhost:" + std::string(argv[1])) << "\n";

  return 0;
}

Then just make sure to have a webserver running at the address specified.

I expected the following

I expected the most recent error to be related to a self-signed cert error.

curl/libcurl version

WARNING: this libcurl is Debug-enabled, do not use in production

curl 8.18.0 (x86_64-pc-linux-gnu) libcurl/8.18.0 OpenSSL/3.6.1 zlib/1.3.1.2-audit
Release-Date: 2026-01-07
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS Debug HSTS HTTPS-proxy IPv6 Largefile libz NTLM SSL threadsafe TLS-SRP TrackMemory UnixSockets

and

WARNING: this libcurl is Debug-enabled, do not use in production

curl 8.17.0 (x86_64-pc-linux-gnu) libcurl/8.17.0 OpenSSL/3.6.1 zlib/1.3.1.2-audit
Release-Date: 2025-11-05
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS Debug HSTS HTTPS-proxy IPv6 Largefile libz NTLM SSL threadsafe TLS-SRP TrackMemory UnixSockets

operating system

Linux 9a71d92e8ff4 5.15.0-139-generic #149~20.04.1-Ubuntu SMP Wed Apr 16 08:29:56 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

and

macOS 17 (Apple toolchain, apple-clang 16 and 17)

and

Windows Server 2019 (MSVC 193)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions