Repository navigation
[BUG] The curl client does not check what curl_global_init returns #4434
Description
Describe your environment main at 3fb1d31, Ubuntu, gcc 14, libcurl 8.14.1, CMake.
HttpCurlGlobalInitializer is the one place the curl client initialises libcurl, and it throws away what that call returns. ext/src/http/client/curl/http_client_curl.cc:
HttpCurlGlobalInitializer::HttpCurlGlobalInitializer()
{
curl_global_init(CURL_GLOBAL_ALL);
}curl_global_init says it plainly: "If this function returns non-zero, something went wrong and you cannot use the other curl functions."
Nothing records that, so nothing can honour it. HttpClient's constructor takes the singleton and then calls curl_multi_init straight after it, which is one of the functions the sentence above is about, and every session after that reaches curl_easy_init the same way.
What is already fixed and what is not
#4404 is about the curl client treating failed allocations as success, and the branch for it checks what curl_easy_init, curl_slist_append, curl_multi_init, curl_multi_cleanup, curl_multi_remove_handle and curl_multi_add_handle return. It also fixed the ordering here, since multi_handle_ is declared before curl_global_initializer_ and member initialisation order meant curl_multi_init used to run before curl_global_init had.
That ordering fix is on the branch for it and not on main: at cdd17eb1, http_client_curl.h still declares CURLM *multi_handle_; at line 388 and curl_global_initializer_ at 409, so curl_multi_init still runs first in HttpClient. Both halves are still open on main, and the condition is the one this issue is about: libcurl is initialised first, but nobody asks whether it was initialised successfully.
What it would take
Two shapes, and the choice is a design one.
The small one records the result in the singleton and has HttpClient's constructor skip initMultiHandle() when it is not CURLE_OK, reporting once. Everything downstream then behaves the way a client with no multi handle already behaves, which after #4404 means requests are refused with a reason rather than sent into libcurl. It costs one member on HttpCurlGlobalInitializer, which is a concrete class in an installed header, so it moves that layout.
The larger one gives the client a way to refuse construction, which is a wider conversation about what an exporter does when its HTTP client cannot exist.
Why I have not sent a patch
I cannot make curl_global_init fail in the test binary, and I would rather say so than ship a branch nothing runs.
The suite installs its allocator callbacks with curl_global_init_mem from SetUpTestSuite, and that call is the global initialisation: it "works exactly as curl_global_init with one addition". It has to run there, because installing the callbacks after libcurl is initialised is a silent no-op. So by the time any client exists libcurl is already initialised, and the curl_global_init inside the singleton is a reference count bump that returns CURLE_OK whatever the allocator does.
Reaching the failure needs a seam that the client calls instead of curl_global_init directly. That is worth discussing on its own terms, since the same seam would answer the other injection questions in this area, but it is production surface added for testability and not something to slip into a bug fix.
Happy to send either shape once you say which, and to write the seam if that is the direction.
Found while working through #4404.
Activity
Dyfintie commentedon Sep 6, 2026
Hello @thc1006
I would like to take up this issue if no one is working on it.
Dyfintie commentedon Sep 6, 2026
Ma'am @thc1006 , I saw the 2 proposed solutions and understood the problem in the code.
I prefer to go with the 1st one , which is the singleton method application.
REASONS :
1 -preserves the api compatibility
2 -maintain the repos error convention (Following the design principles used in the repo)
3 -to avoid exporter side boilerplate bloating ie the exporter would need to create error handlers
4- This is a Low-risk fix (as it doesn't demand change of multiple features/files in the repo)
Plan of Action :
1 - within HttpCurlGlobalInitializer Record the CURLcode and track initialization state
2 - Log via OTEL_INTERNAL_LOG_ERROR if curl_global_init returns non-zero
3- In
~HttpCurlGlobalInitializer(), only invokecurl_global_cleanup()if initialization actually succeeded (per libcurl specifications)4 - Fix issues regarding the HttpClient and HttpClientSync as well
Please let me know if this sounds good, and I will submit a PR
following this plan!
[BUG] Check what curl_global_init returns (open-telemetry#4434)
thc1006 commentedon Sep 8, 2026
Yes, please do, and sorry for the slow reply.
Your reasoning for the singleton is the same one I would have given, and #4531 already implements it. I have read it and left notes on the pull request rather than here, since they are about the code.
[BUG] Check what curl_global_init returns (open-telemetry#4434)
[BUG] Check what curl_global_init returns (open-telemetry#4434)
[BUG] Check what curl_global_init returns (open-telemetry#4434)
[BUG] Check what curl_global_init returns (open-telemetry#4434)