ci, iwyu: Fix warnings in `src/util` and treat them as errors
What changed, and why it matters
This commit is a routine code-quality cleanup. It adjusts which C++ header files are included in various source files under src/util and turns on a stricter automated check (IWYU) in the project's continuous integration. There is no functional change to Bitcoin Core's behavior, no bug fix, and no security-relevant change.
No security action required. Treat as normal maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit applies Include-What-You-Use (IWYU) fixes across src/util and adds src/util/.*.cpp to the CI-enforced IWYU pattern. Changes are limited to adding, removing, or reordering #include directives and minor forward declarations (e.g., class CThreadInterrupt in sock.h). No logic, interfaces, or runtime behavior is modified. The commit message explicitly frames this as a CI/IWYU cleanup.
Changed components
src/util/* (header include lists only)ci/test/03_test_script.sh (IWYU enforcement regex)Inspect captured patch +100 / −57
diff --git a/ci/test/03_test_script.sh b/ci/test/03_test_script.sh
index 9d6351af..4e4d9757 100755
--- a/ci/test/03_test_script.sh
+++ b/ci/test/03_test_script.sh
@@ -209,7 +209,7 @@ fi
if [[ "${RUN_IWYU}" == true ]]; then
# TODO: Consider enforcing IWYU across the entire codebase.
- FILES_WITH_ENFORCED_IWYU="/src/(((crypto|index|kernel|primitives|univalue/(lib|test)|zmq)/.*|common/license_info|node/blockstorage|node/utxo_snapshot|clientversion|core_io|signet)\\.cpp)"
+ FILES_WITH_ENFORCED_IWYU="/src/(((crypto|index|kernel|primitives|univalue/(lib|test)|util|zmq)/.*|common/license_info|node/blockstorage|node/utxo_snapshot|clientversion|core_io|signet)\\.cpp)"
jq --arg patterns "$FILES_WITH_ENFORCED_IWYU" 'map(select(.file | test($patterns)))' "${BASE_BUILD_DIR}/compile_commands.json" > "${BASE_BUILD_DIR}/compile_commands_iwyu_errors.json"
jq --arg patterns "$FILES_WITH_ENFORCED_IWYU" 'map(select(.file | test($patterns) | not))' "${BASE_BUILD_DIR}/compile_commands.json" > "${BASE_BUILD_DIR}/compile_commands_iwyu_warnings.json"
diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp
index 7d4e1887..c00de181 100644
--- a/src/bench/strencodings.cpp
+++ b/src/bench/strencodings.cpp
@@ -4,6 +4,7 @@
#include <bench/bench.h>
#include <consensus/consensus.h>
+#include <crypto/hex_base.h>
#include <random.h>
#include <span.h>
#include <util/strencodings.h>
diff --git a/src/logging.h b/src/logging.h
index 005c67fd..069a73ea 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -8,6 +8,7 @@
#include <crypto/siphash.h>
#include <logging/categories.h> // IWYU pragma: export
+#include <span.h>
#include <util/fs.h>
#include <util/log.h> // IWYU pragma: export
#include <util/stdmutex.h>
diff --git a/src/uint256.h b/src/uint256.h
index d4204275..3fe44ab7 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -7,6 +7,7 @@
#define BITCOIN_UINT256_H
#include <crypto/common.h>
+#include <crypto/hex_base.h>
#include <span.h>
#include <util/strencodings.h>
#include <util/string.h>
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index f8b5a527..04e47c24 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -4,20 +4,18 @@
#include <util/asmap.h>
-#include <clientversion.h>
#include <hash.h>
-#include <serialize.h>
#include <streams.h>
#include <uint256.h>
+#include <util/check.h>
#include <util/fs.h>
#include <util/log.h>
-#include <algorithm>
#include <bit>
-#include <cassert>
#include <cstddef>
#include <cstdio>
#include <span>
+#include <string>
#include <utility>
#include <vector>
diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp
index db40bfb5..2488eacf 100644
--- a/src/util/bip32.cpp
+++ b/src/util/bip32.cpp
@@ -2,12 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <tinyformat.h>
#include <util/bip32.h>
+
+#include <tinyformat.h>
#include <util/strencodings.h>
#include <cstdint>
#include <cstdio>
+#include <optional>
#include <sstream>
bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp
index 943517ad..40930301 100644
--- a/src/util/bytevectorhash.cpp
+++ b/src/util/bytevectorhash.cpp
@@ -2,10 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/bytevectorhash.h>
+
#include <crypto/siphash.h>
#include <random.h>
-#include <util/bytevectorhash.h>
+#include <span>
#include <vector>
ByteVectorHash::ByteVectorHash() :
diff --git a/src/util/chaintype.cpp b/src/util/chaintype.cpp
index 5059ff7e..6029002a 100644
--- a/src/util/chaintype.cpp
+++ b/src/util/chaintype.cpp
@@ -4,7 +4,8 @@
#include <util/chaintype.h>
-#include <cassert>
+#include <util/check.h>
+
#include <optional>
#include <string>
diff --git a/src/util/chaintype.h b/src/util/chaintype.h
index 3b246ea4..caae77c1 100644
--- a/src/util/chaintype.h
+++ b/src/util/chaintype.h
@@ -7,6 +7,7 @@
#include <optional>
#include <string>
+#include <string_view>
enum class ChainType {
MAIN,
diff --git a/src/util/check.h b/src/util/check.h
index 34801ca0..4f5b0010 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -8,11 +8,14 @@
#include <attributes.h>
#include <atomic>
+// We use `util/check.h` to provide the `assert()` macro
+// to ensure that `NDEBUG` is not defined.
#include <cassert> // IWYU pragma: export
#include <source_location>
#include <stdexcept>
#include <string>
#include <string_view>
+#include <type_traits>
#include <utility>
constexpr bool G_FUZZING_BUILD{
diff --git a/src/util/exec.cpp b/src/util/exec.cpp
index 6b140613..87d11237 100644
--- a/src/util/exec.cpp
+++ b/src/util/exec.cpp
@@ -5,12 +5,17 @@
#include <util/exec.h>
#include <util/fs.h>
+#ifdef WIN32
#include <util/subprocess.h>
+#endif
+#include <cstdlib>
#include <string>
-#include <vector>
+#include <system_error>
#ifdef WIN32
+#include <codecvt>
+#include <locale>
#include <process.h>
#include <windows.h>
#else
diff --git a/src/util/expected.h b/src/util/expected.h
index 66fb98e0..c88c6de4 100644
--- a/src/util/expected.h
+++ b/src/util/expected.h
@@ -8,7 +8,6 @@
#include <attributes.h>
#include <util/check.h>
-#include <cassert>
#include <exception>
#include <utility>
#include <variant>
diff --git a/src/util/feefrac.cpp b/src/util/feefrac.cpp
index 68ba2b66..088149be 100644
--- a/src/util/feefrac.cpp
+++ b/src/util/feefrac.cpp
@@ -3,9 +3,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/feefrac.h>
-#include <algorithm>
+
+#include <util/check.h>
+
#include <array>
-#include <vector>
+#include <cstddef>
std::partial_ordering CompareChunks(std::span<const FeeFrac> chunks0, std::span<const FeeFrac> chunks1)
{
diff --git a/src/util/feefrac.h b/src/util/feefrac.h
index 25d87d34..30ec6b02 100644
--- a/src/util/feefrac.h
+++ b/src/util/feefrac.h
@@ -5,13 +5,13 @@
#ifndef BITCOIN_UTIL_FEEFRAC_H
#define BITCOIN_UTIL_FEEFRAC_H
-#include <span.h>
#include <util/check.h>
#include <util/overflow.h>
#include <compare>
#include <cstdint>
-#include <vector>
+#include <span>
+#include <utility>
/** Data structure storing a fee and size, ordered by increasing fee/size.
*
diff --git a/src/util/fs.cpp b/src/util/fs.cpp
index 692f6718..88966ab0 100644
--- a/src/util/fs.cpp
+++ b/src/util/fs.cpp
@@ -3,23 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/fs.h>
+
+#include <util/check.h>
#include <util/syserror.h>
+#include <cerrno>
+#include <string>
+
#ifndef WIN32
-#include <cstring>
#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/utsname.h>
#include <unistd.h>
#else
#include <limits>
#include <windows.h>
#endif
-#include <cassert>
-#include <cerrno>
-#include <string>
-
namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode)
diff --git a/src/util/fs.h b/src/util/fs.h
index dce371cc..73d69479 100644
--- a/src/util/fs.h
+++ b/src/util/fs.h
@@ -5,17 +5,18 @@
#ifndef BITCOIN_UTIL_FS_H
#define BITCOIN_UTIL_FS_H
-#include <tinyformat.h>
+// IWYU incorrectly suggests removing this header.
+// See https://github.com/include-what-you-use/include-what-you-use/issues/1931.
+#include <tinyformat.h> // IWYU pragma: keep
#include <cstdio>
+// The `util/fs.h` header is designed to be a drop-in replacement for `filesystem`.
#include <filesystem> // IWYU pragma: export
#include <functional>
#include <iomanip>
#include <ios>
-#include <ostream>
#include <string>
#include <string_view>
-#include <system_error>
#include <type_traits>
#include <utility>
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index e7780d74..8e08e66d 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -24,6 +24,7 @@
#ifndef WIN32
#include <fcntl.h>
#include <sys/resource.h>
+#include <sys/types.h>
#include <unistd.h>
#else
#include <io.h>
diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h
index d39ae115..face17fd 100644
--- a/src/util/fs_helpers.h
+++ b/src/util/fs_helpers.h
@@ -13,6 +13,7 @@
#include <iosfwd>
#include <limits>
#include <optional>
+#include <string>
#ifdef __APPLE__
enum class FSType {
diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp
index 3d5ffcf8..b12f7451 100644
--- a/src/util/hasher.cpp
+++ b/src/util/hasher.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/hasher.h>
+
#include <crypto/siphash.h>
#include <random.h>
-#include <span.h>
-#include <util/hasher.h>
SaltedUint256Hasher::SaltedUint256Hasher() : m_hasher{
FastRandomContext().rand64(),
diff --git a/src/util/hasher.h b/src/util/hasher.h
index 02c77033..7e74c676 100644
--- a/src/util/hasher.h
+++ b/src/util/hasher.h
@@ -8,12 +8,11 @@
#include <crypto/common.h>
#include <crypto/siphash.h>
#include <primitives/transaction.h>
-#include <span.h>
#include <uint256.h>
-#include <concepts>
#include <cstdint>
#include <cstring>
+#include <span>
class SaltedUint256Hasher
{
diff --git a/src/util/obfuscation.h b/src/util/obfuscation.h
index e9a2e609..a5df75ec 100644
--- a/src/util/obfuscation.h
+++ b/src/util/obfuscation.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_OBFUSCATION_H
#define BITCOIN_UTIL_OBFUSCATION_H
-#include <cstdint>
+#include <crypto/hex_base.h>
#include <span.h>
#include <tinyformat.h>
#include <util/strencodings.h>
@@ -13,6 +13,7 @@
#include <array>
#include <bit>
#include <climits>
+#include <cstdint>
#include <ios>
#include <memory>
diff --git a/src/util/overflow.h b/src/util/overflow.h
index 48df3549..274ba045 100644
--- a/src/util/overflow.h
+++ b/src/util/overflow.h
@@ -5,7 +5,8 @@
#ifndef BITCOIN_UTIL_OVERFLOW_H
#define BITCOIN_UTIL_OVERFLOW_H
-#include <cassert>
+#include <util/check.h>
+
#include <climits>
#include <concepts>
#include <limits>
diff --git a/src/util/rbf.cpp b/src/util/rbf.cpp
index bc28c6bb..82ef020d 100644
--- a/src/util/rbf.cpp
+++ b/src/util/rbf.cpp
@@ -6,6 +6,8 @@
#include <primitives/transaction.h>
+#include <vector>
+
bool SignalsOptInRBF(const CTransaction &tx)
{
for (const CTxIn &txin : tx.vin) {
diff --git a/src/util/readwritefile.cpp b/src/util/readwritefile.cpp
index 82b596f9..6a9eeb28 100644
--- a/src/util/readwritefile.cpp
+++ b/src/util/readwritefile.cpp
@@ -9,7 +9,6 @@
#include <algorithm>
#include <cstdio>
-#include <limits>
#include <string>
#include <utility>
diff --git a/src/util/readwritefile.h b/src/util/readwritefile.h
index 2a9ccf5f..54a5a305 100644
--- a/src/util/readwritefile.h
+++ b/src/util/readwritefile.h
@@ -7,6 +7,7 @@
#include <util/fs.h>
+#include <cstddef>
#include <limits>
#include <string>
#include <utility>
diff --git a/src/util/signalinterrupt.h b/src/util/signalinterrupt.h
index 027dd153..5a23cd1e 100644
--- a/src/util/signalinterrupt.h
+++ b/src/util/signalinterrupt.h
@@ -13,7 +13,6 @@
#endif
#include <atomic>
-#include <cstdlib>
namespace util {
/**
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index a06ab7a7..8e0c0f47 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -4,18 +4,23 @@
#include <util/sock.h>
-#include <common/system.h>
#include <compat/compat.h>
#include <span.h>
#include <tinyformat.h>
+#include <util/check.h>
#include <util/log.h>
#include <util/syserror.h>
#include <util/threadinterrupt.h>
#include <util/time.h>
+#include <algorithm>
+#include <compare>
+#include <exception>
#include <memory>
#include <stdexcept>
#include <string>
+#include <utility>
+#include <vector>
#ifdef USE_POLL
#include <poll.h>
diff --git a/src/util/sock.h b/src/util/sock.h
index 8c51b8ea..e20b31e1 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -6,15 +6,17 @@
#define BITCOIN_UTIL_SOCK_H
#include <compat/compat.h>
-#include <util/threadinterrupt.h>
#include <util/time.h>
-#include <chrono>
+#include <cstdint>
+#include <limits>
#include <memory>
#include <span>
#include <string>
#include <unordered_map>
+class CThreadInterrupt;
+
/**
* Maximum time to wait for I/O readiness.
* It will take up until this time to break off in case of an interruption.
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index ff593885..e64b677f 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -7,14 +7,13 @@
#include <crypto/hex_base.h>
#include <span.h>
+#include <util/check.h>
#include <util/overflow.h>
-#include <array>
-#include <cassert>
-#include <cstring>
+#include <compare>
#include <limits>
#include <optional>
-#include <ostream>
+#include <sstream>
#include <string>
#include <vector>
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index faff83bb..e5279722 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -9,11 +9,9 @@
#ifndef BITCOIN_UTIL_STRENCODINGS_H
#define BITCOIN_UTIL_STRENCODINGS_H
-#include <crypto/hex_base.h>
#include <span.h>
#include <util/string.h>
-#include <algorithm>
#include <array>
#include <bit>
#include <charconv>
@@ -21,6 +19,7 @@
#include <cstdint>
#include <limits>
#include <optional>
+#include <span>
#include <string>
#include <string_view>
#include <system_error>
diff --git a/src/util/string.cpp b/src/util/string.cpp
index c3b4b474..6e86095a 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -4,7 +4,10 @@
#include <util/string.h>
+#include <iterator>
+#include <memory>
#include <regex>
+#include <stdexcept>
#include <string>
namespace util {
diff --git a/src/util/string.h b/src/util/string.h
index 89e13099..20c78583 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -5,13 +5,14 @@
#ifndef BITCOIN_UTIL_STRING_H
#define BITCOIN_UTIL_STRING_H
-#include <span.h>
-
+#include <algorithm>
#include <array>
+#include <cstddef>
#include <cstdint>
-#include <cstring>
+#include <initializer_list>
#include <locale>
#include <optional>
+#include <span>
#include <sstream>
#include <string>
#include <string_view>
diff --git a/src/util/subprocess.h b/src/util/subprocess.h
index 8b917130..3d01f4b7 100644
--- a/src/util/subprocess.h
+++ b/src/util/subprocess.h
@@ -36,10 +36,10 @@ Documentation for C++ subprocessing library.
#ifndef BITCOIN_UTIL_SUBPROCESS_H
#define BITCOIN_UTIL_SUBPROCESS_H
+#include <util/check.h>
#include <util/syserror.h>
#include <algorithm>
-#include <cassert>
#include <csignal>
#include <cstdio>
#include <cstdlib>
diff --git a/src/util/syserror.cpp b/src/util/syserror.cpp
index e06ed0cd..e7637afe 100644
--- a/src/util/syserror.cpp
+++ b/src/util/syserror.cpp
@@ -4,9 +4,10 @@
#include <bitcoin-build-config.h> // IWYU pragma: keep
-#include <tinyformat.h>
#include <util/syserror.h>
+#include <tinyformat.h>
+
#include <cstring>
#include <string>
diff --git a/src/util/thread.cpp b/src/util/thread.cpp
index 0fde73c4..5b20e807 100644
--- a/src/util/thread.cpp
+++ b/src/util/thread.cpp
@@ -11,7 +11,6 @@
#include <exception>
#include <functional>
#include <string>
-#include <utility>
void util::TraceThread(std::string_view thread_name, std::function<void()> thread_func)
{
diff --git a/src/util/thread.h b/src/util/thread.h
index cb1dd86a..d398b188 100644
--- a/src/util/thread.h
+++ b/src/util/thread.h
@@ -6,7 +6,7 @@
#define BITCOIN_UTIL_THREAD_H
#include <functional>
-#include <string>
+#include <string_view>
namespace util {
/**
diff --git a/src/util/threadinterrupt.h b/src/util/threadinterrupt.h
index 9cac330e..ba45f117 100644
--- a/src/util/threadinterrupt.h
+++ b/src/util/threadinterrupt.h
@@ -6,9 +6,9 @@
#define BITCOIN_UTIL_THREADINTERRUPT_H
#include <sync.h>
+#include <util/time.h>
#include <atomic>
-#include <chrono>
#include <condition_variable>
/**
diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp
index 310f60f6..0615b331 100644
--- a/src/util/threadnames.cpp
+++ b/src/util/threadnames.cpp
@@ -2,18 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/threadnames.h>
+
+#include <algorithm>
#include <cstring>
#include <string>
-#include <thread>
-#include <utility>
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
#include <pthread.h>
#include <pthread_np.h>
#endif
-#include <util/threadnames.h>
-
#if __has_include(<sys/prctl.h>)
#include <sys/prctl.h>
#endif
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 9e0715e5..6a199ebc 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -5,7 +5,6 @@
#include <util/time.h>
-#include <compat/compat.h>
#include <tinyformat.h>
#include <util/check.h>
#include <util/strencodings.h>
@@ -13,11 +12,18 @@
#include <array>
#include <atomic>
#include <chrono>
+#include <compare>
#include <optional>
#include <string>
#include <string_view>
#include <thread>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
static constexpr std::array<std::string_view, 7> weekdays{"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"}; // 1970-01-01 was a Thursday.
static constexpr std::array<std::string_view, 12> months{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
diff --git a/src/util/time.h b/src/util/time.h
index 30d363bb..46307989 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -9,10 +9,17 @@
// The `util/time.h` header is designed to be a drop-in replacement for `chrono`.
#include <chrono> // IWYU pragma: export
#include <cstdint>
+#include <ctime>
#include <optional>
#include <string>
#include <string_view>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
using namespace std::chrono_literals;
/// Version of the system clock that is mockable in the context of tests (via
diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp
index c982fa6f..6f701e45 100644
--- a/src/util/tokenpipe.cpp
+++ b/src/util/tokenpipe.cpp
@@ -1,15 +1,18 @@
// Copyright (c) 2021-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/tokenpipe.h>
#include <bitcoin-build-config.h> // IWYU pragma: keep
+#include <util/tokenpipe.h>
+
#ifndef WIN32
#include <cerrno>
-#include <fcntl.h>
#include <optional>
+
+#include <fcntl.h>
+#include <sys/types.h>
#include <unistd.h>
TokenPipeEnd TokenPipe::TakeReadEnd()
diff --git a/src/util/translation.h b/src/util/translation.h
index cc29eef6..26fb4b8c 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -6,9 +6,9 @@
#define BITCOIN_UTIL_TRANSLATION_H
#include <tinyformat.h>
+#include <util/check.h>
#include <util/string.h>
-#include <cassert>
#include <functional>
#include <string>
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.