-
Notifications
You must be signed in to change notification settings - Fork 16
Description
✅ I checked the Altinity Stable Builds lifecycle table, and the Altinity Stable Build version I'm using is still supported.
Type of problem
Bug report - something's broken
Describe the situation
After PR #1387 disabled crash reporting by setting send_crash_reports.enabled=false and clearing the endpoint in embedded.xml, the crash report is no longer uploaded to crash.clickhouse.com (confirmed via tcpdump). However, the crash-report sending code path is still executed during a crash, resulting in a BAD_ARGUMENTS exception (Empty protocol in the URL).
This happens because CrashWriter::initialize() always creates a CrashWriter instance regardless of the enabled setting. When a crash occurs, CrashWriter::onSignal() checks if (instance) — which is always true — and proceeds to call sendError(), which tries to construct an HTTP request with an empty endpoint URL and throws.
This issue:
- Produces misleading error log output during crashes
- Executes unnecessary code in a crash handler, where minimal work is preferred
- Affects all builds that include the
embedded.xmlchange from PR Antalya 25.8 - disable crash report in more places #1387
How to reproduce the behavior
Environment
- Version: 25.8.14.20001.altinityantalya (PR Antalya 25.8 - disable crash report in more places #1387)
Steps
- Start the ClickHouse server built from the PR Antalya 25.8 - disable crash report in more places #1387 branch
- Get the server PID and send a SIGSEGV:
kill -SEGV $(pidof clickhouse-server)- Observe the server log output
Expected behavior
When crash reporting is disabled, the send path should be fully skipped — no send attempt and no exception:
<Information> CrashWriter: Not sending crash report
Actual behavior
The server attempts to send the crash report and fails with an exception:
2026.02.20 14:20:57.332260 [ 2316516 ] {} <Information> CrashWriter: Sending crash report
2026.02.20 14:20:57.335015 [ 2316516 ] {} <Information> CrashWriter: Cannot send a crash report: Code: 36. DB::Exception: Empty protocol in the URL. (BAD_ARGUMENTS), Stack trace
(when copying this message, always include the lines below):
0. ./ci/tmp/build/./src/Common/Exception.cpp:130: DB::Exception::Exception(DB::Exception::MessageMasked&&, int, bool) @ 0x00000000135db95f
1. DB::Exception::Exception(String&&, int, String, bool) @ 0x000000000ca82b8e
2. DB::Exception::Exception(PreformattedMessage&&, int) @ 0x000000000ca82640
3. DB::Exception::Exception<>(int, FormatStringHelperImpl<>) @ 0x000000000ca916eb
4. ./src/Common/ProxyConfiguration.h:34: DB::ProxyConfiguration::protocolFromString(String const&) @ 0x00000000139f53be
5. ./ci/tmp/build/./src/IO/WriteBufferFromHTTP.cpp:78: DB::BuilderWriteBufferFromHTTP::create() @ 0x00000000139f3fe3
6. ./ci/tmp/build/./src/Daemon/CrashWriter.cpp:77: CrashWriter::sendError(CrashWriter::Type, int, std::basic_string_view<char, std::char_traits<char>>, std::array<void*, 45ul>
const&, unsigned long, unsigned long) @ 0x0000000016220d3a
7. ./src/Daemon/CrashWriter.cpp:54: SignalListener::onFault(int, siginfo_t const&, ucontext_t, StackTrace const&, std::vector<std::array<void, 45ul>,
std::allocator<std::array<void, 45ul>>> const&, unsigned int, DB::ThreadStatus) const @ 0x0000000016217bf2
8. ./ci/tmp/build/./src/Common/SignalHandlers.cpp:335: SignalListener::run() @ 0x000000001620de3e
9. ./base/poco/Foundation/src/Thread_POSIX.cpp:341: Poco::ThreadImpl::runnableEntry(void*) @ 0x000000001f30b9c1
10. start_thread @ 0x000000000009caa4
11. clone3 @ 0x0000000000129c6c
(version 25.8.14.20001.altinityantalya)
Root cause analysis
In src/Daemon/CrashWriter.cpp, initialize() unconditionally creates the singleton instance:
void CrashWriter::initialize(Poco::Util::LayeredConfiguration & config)
{
instance.reset(new CrashWriter(config));
}The constructor skips setting the endpoint when enabled=false, leaving it as an empty string. But since instance is non-null, the guard in sendError() does not short-circuit:
void CrashWriter::sendError(...)
{
if (!instance) // always false — instance is always created
{
LOG_INFO(logger, "Not sending crash report");
return;
}
// proceeds to use empty endpoint → exception
}Suggested fix
Don't create the instance when crash reporting is disabled:
void CrashWriter::initialize(Poco::Util::LayeredConfiguration & config)
{
if (config.getBool("send_crash_reports.enabled", false))
instance.reset(new CrashWriter(config));
}This way the existing if (instance) guards in onSignal() and onException() will correctly skip the send path.
Additional context
Related PR
- PR Antalya 25.8 - disable crash report in more places #1387: Disabled crash reporting in
embedded.xmlandconfig.yaml.example
Network verification
tcpdumpconfirms no data is sent tocrash.clickhouse.comafter PR Antalya 25.8 - disable crash report in more places #1387 — the PR achieves its goal- The issue is limited to unnecessary exception noise in the crash handler logs