diff --git a/.github/workflows/skyr-url-ci.yml b/.github/workflows/skyr-url-ci.yml
index a5cd7813..1d5f22a1 100644
--- a/.github/workflows/skyr-url-ci.yml
+++ b/.github/workflows/skyr-url-ci.yml
@@ -476,8 +476,6 @@ jobs:
           set(BUILD_V2 OFF)
           if ("${{ matrix.config.name }}" STREQUAL "Windows MSVC 2019 Debug (C++20)" OR
               "${{ matrix.config.name }}" STREQUAL "Windows MSVC 2019 Release (C++20)" OR
-              "${{ matrix.config.name }}" STREQUAL "Linux GCC 10 Debug (C++20)" OR
-              "${{ matrix.config.name }}" STREQUAL "Linux GCC 10 Release (C++20)" OR
               "${{ matrix.config.name }}" STREQUAL "Linux GCC 11 Debug (C++20)" OR
               "${{ matrix.config.name }}" STREQUAL "Linux GCC 11 Release (C++20)" OR
               "${{ matrix.config.name }}" STREQUAL "Linux Clang 11 Debug (C++20)" OR
diff --git a/include/skyr/v2/containers/static_vector.hpp b/include/skyr/v2/containers/static_vector.hpp
index 3be1359a..304cb256 100644
--- a/include/skyr/v2/containers/static_vector.hpp
+++ b/include/skyr/v2/containers/static_vector.hpp
@@ -10,6 +10,7 @@
 #include <array>
 #include <type_traits>
 #include <optional>
+#include <cassert>
 
 namespace skyr::inline v2 {
 ///
@@ -51,14 +52,15 @@ class static_vector {
   constexpr auto operator=(const static_vector &) -> static_vector & = default;
   constexpr auto operator=(static_vector &&) noexcept -> static_vector & = default;
 
-  ~static_vector() {
+  constexpr ~static_vector() {
     clear();
   }
 
   /// Gets the first const element in the vector
   /// \return a const T &
-  /// \pre `size() > 0`
+  /// \pre `size_ > 0`
   constexpr auto front() const noexcept -> const_reference {
+    assert(size() > 0);
     return impl_[0];
   }
 
@@ -66,6 +68,7 @@ class static_vector {
   /// \return a T &
   /// \pre `size() > 0`
   constexpr auto front() noexcept -> reference {
+    assert(size_ > 0);
     return impl_[0];
   }
 
@@ -73,6 +76,7 @@ class static_vector {
   /// \return
   /// \pre `size() > 0`
   constexpr auto back() const noexcept -> const_reference {
+    assert(size_ > 0);
     return impl_[size_ - 1];
   }
 
@@ -80,6 +84,7 @@ class static_vector {
   /// \return
   /// \pre `size() > 0`
   constexpr auto back() noexcept -> reference {
+    assert(size_ > 0);
     return impl_[size_ - 1];
   }
 
@@ -89,6 +94,7 @@ class static_vector {
   /// \pre `size() < capacity()`
   /// \post `size() > 0 && size() <= capacity()`
   constexpr auto push_back(const_reference value) noexcept -> reference {
+    assert(size_ < Capacity);
     impl_[size_++] = value;
     return impl_[size_ - 1];
   }
@@ -101,6 +107,7 @@ class static_vector {
   /// \post `size() > 0 && size() <= capacity()`
   template <class... Args>
   constexpr auto emplace_back(Args &&... args) noexcept(std::is_trivially_move_assignable_v<T>) -> reference {
+    assert(size_ < Capacity);
     impl_[size_++] = value_type{std::forward<Args>(args)...};
     return back();
   }
@@ -108,6 +115,7 @@ class static_vector {
   ///
   /// \pre `size() > 0`
   constexpr void pop_back() noexcept {
+    assert(size_ > 0);
     back().~value_type();
     --size_;
   }
diff --git a/include/skyr/v2/core/host.hpp b/include/skyr/v2/core/host.hpp
index 272828a4..671c37dc 100644
--- a/include/skyr/v2/core/host.hpp
+++ b/include/skyr/v2/core/host.hpp
@@ -86,7 +86,7 @@ class host {
 
   ///
   /// \return \c true if the host is a domain, \c false otherwise
-  [[nodiscard]] auto is_domain_name() const noexcept {
+  [[nodiscard]] constexpr auto is_domain_name() const noexcept {
     return std::holds_alternative<skyr::v2::domain_name>(host_);
   }
 
@@ -98,31 +98,31 @@ class host {
 
   ///
   /// \return \c true if the host is an IPv4 address, \c false otherwise
-  [[nodiscard]] auto is_ipv4_address() const noexcept {
+  [[nodiscard]] constexpr auto is_ipv4_address() const noexcept {
     return std::holds_alternative<skyr::v2::ipv4_address>(host_);
   }
 
   ///
   /// \return
-  [[nodiscard]] auto to_ipv4_address() const noexcept {
+  [[nodiscard]] constexpr auto to_ipv4_address() const noexcept {
     return is_ipv4_address() ? std::make_optional(std::get<skyr::v2::ipv4_address>(host_)) : std::nullopt;
   }
 
   ///
   /// \return \c true if the host is an IPv6 address, \c false otherwise
-  [[nodiscard]] auto is_ipv6_address() const noexcept {
+  [[nodiscard]] constexpr auto is_ipv6_address() const noexcept {
     return std::holds_alternative<skyr::v2::ipv6_address>(host_);
   }
 
   ///
   /// \return
-  [[nodiscard]] auto to_ipv6_address() const noexcept {
+  [[nodiscard]] constexpr auto to_ipv6_address() const noexcept {
     return is_ipv6_address() ? std::make_optional(std::get<skyr::v2::ipv6_address>(host_)) : std::nullopt;
   }
 
   ///
   /// \return \c true if the host is an opaque host, \c false otherwise
-  [[nodiscard]] auto is_opaque_host() const noexcept {
+  [[nodiscard]] constexpr auto is_opaque_host() const noexcept {
     return std::holds_alternative<skyr::v2::opaque_host>(host_);
   }
 
@@ -134,7 +134,7 @@ class host {
 
   ///
   /// \return
-  [[nodiscard]] auto is_empty() const noexcept {
+  [[nodiscard]] constexpr auto is_empty() const noexcept {
     return std::holds_alternative<empty_host>(host_);
   }
 
diff --git a/include/skyr/v2/core/url_parser_context.hpp b/include/skyr/v2/core/url_parser_context.hpp
index 0a93eea6..b30275e5 100644
--- a/include/skyr/v2/core/url_parser_context.hpp
+++ b/include/skyr/v2/core/url_parser_context.hpp
@@ -27,7 +27,7 @@ using namespace std::string_literals;
 using namespace std::string_view_literals;
 
 namespace details {
-inline auto contains(std::string_view view, char element) noexcept {
+constexpr inline auto contains(std::string_view view, char element) noexcept {
   auto first = std::cbegin(view), last = std::cend(view);
   return last != std::find(first, last, element);
 }
@@ -38,7 +38,7 @@ inline auto port_number(std::string_view port) noexcept -> tl::expected<std::uin
   }
 
   const char *port_first = port.data();
-  char *port_last = nullptr;
+  char *port_last = nullptr; // NOLINT
   auto port_value = std::strtoul(port_first, &port_last, 10);
 
   if (port_first == port_last) {
@@ -55,7 +55,7 @@ inline auto is_url_code_point(char byte) noexcept {
   return std::isalnum(byte, std::locale::classic()) || contains("!$&'()*+,-./:;=?@_~"sv, byte);
 }
 
-inline auto is_windows_drive_letter(std::string_view segment) noexcept {
+constexpr inline auto is_windows_drive_letter(std::string_view segment) noexcept {
   if (segment.size() < 2) {
     return false;
   }
@@ -73,11 +73,11 @@ inline auto is_windows_drive_letter(std::string_view segment) noexcept {
   return result;
 }
 
-inline auto is_single_dot_path_segment(std::string_view segment) noexcept {
+constexpr inline auto is_single_dot_path_segment(std::string_view segment) noexcept {
   return (segment == ".") || (segment == "%2e") || (segment == "%2E");
 }
 
-inline auto is_double_dot_path_segment(std::string_view segment) noexcept {
+constexpr inline auto is_double_dot_path_segment(std::string_view segment) noexcept {
   return (segment == "..") || (segment == "%2e.") || (segment == ".%2e") || (segment == "%2e%2e") ||
          (segment == "%2E.") || (segment == ".%2E") || (segment == "%2E%2E") || (segment == "%2E%2e") ||
          (segment == "%2e%2E");
diff --git a/include/skyr/v2/domain/punycode.hpp b/include/skyr/v2/domain/punycode.hpp
index ea5d0799..640ddd34 100644
--- a/include/skyr/v2/domain/punycode.hpp
+++ b/include/skyr/v2/domain/punycode.hpp
@@ -138,7 +138,7 @@ inline auto punycode_encode(std::u32string_view input, std::string *output) -> t
 /// \param input An ASCII encoded domain to be decoded
 /// \returns The decoded UTF-8 domain, or an error
 template <class StringView>
-inline auto punycode_decode(StringView input, std::u32string *output) -> tl::expected<void, domain_errc> {
+constexpr inline auto punycode_decode(StringView input, std::u32string *output) -> tl::expected<void, domain_errc> {
   using namespace punycode::constants;
 
   // decode_digit(cp) returns the numeric value of a basic code
diff --git a/include/skyr/v2/network/ipv4_address.hpp b/include/skyr/v2/network/ipv4_address.hpp
index 36e309f9..efdd5301 100644
--- a/include/skyr/v2/network/ipv4_address.hpp
+++ b/include/skyr/v2/network/ipv4_address.hpp
@@ -108,7 +108,7 @@ constexpr inline auto parse_ipv4_number(std::string_view input, bool *validation
 /// Parses an IPv4 address
 /// \param input An input string
 /// \returns An `ipv4_address` object or an error
-inline auto parse_ipv4_address(std::string_view input, bool *validation_error)
+constexpr inline auto parse_ipv4_address(std::string_view input, bool *validation_error)
     -> tl::expected<ipv4_address, ipv4_address_errc> {
   using namespace std::string_view_literals;
 
diff --git a/include/skyr/v2/percent_encoding/percent_encoded_char.hpp b/include/skyr/v2/percent_encoding/percent_encoded_char.hpp
index ce119387..1101f1d2 100644
--- a/include/skyr/v2/percent_encoding/percent_encoded_char.hpp
+++ b/include/skyr/v2/percent_encoding/percent_encoded_char.hpp
@@ -208,13 +208,13 @@ struct percent_encoded_char {
 
   ///
   /// \return
-  [[nodiscard]] auto to_string() const & -> std::string {
+  [[nodiscard]] constexpr auto to_string() const & -> const std::string & {
     return impl_;
   }
 
   ///
   /// \return
-  [[nodiscard]] auto to_string() && noexcept -> std::string && {
+  [[nodiscard]] constexpr auto to_string() && noexcept -> std::string && {
     return std::move(impl_);
   }
 
diff --git a/src/v1/url/url.cpp b/src/v1/url/url.cpp
index b820de1c..4052d1a7 100644
--- a/src/v1/url/url.cpp
+++ b/src/v1/url/url.cpp
@@ -17,7 +17,7 @@ void url::initialize(string_view input, const url_record *base) {
 
   bool validation_error = false;
   details::parse(input, &validation_error, base)
-      .and_then([=](auto &&url) -> result_type {
+      .and_then([this](auto &&url) -> result_type {
         update_record(std::forward<url_record>(url));
         return {};
       })
