You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT: from_json's message breaks for invalid UTF-8 and custom string_t #5667
The from_json generated by NLOHMANN_JSON_SERIALIZE_ENUM_STRICT builds its error message with "..." + j.dump(). This has two consequences:
If the unmatched JSON value is (or contains) a string with invalid UTF-8, j.dump() throws type_error.316 while the message is being built, so the caller gets type_error.316 instead of the documented out_of_range.410. Such strings reach get<Enum>() for example from from_cbor()/from_msgpack(), which do not validate UTF-8 (from_cbor()/from_msgpack() do not validate UTF-8 in text strings at decode time (only dump() does) #5529), or from strings assigned by the program.
With a custom string_t, j.dump() returns string_t, and const char* + string_t does not compile unless the type happens to provide that operator+ (not among the documented StringType requirements), and the result must also convert to the const std::string& that out_of_range::create takes. For example, get<Color>() with the alt_json type from tests/src/unit-alt-string.cpp fails with error: invalid operands to binary expression ('const char[36]' and 'string_t' (aka 'alt_string')) at macro_scope.hpp:339.
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE": " + j.dump(), &j));
Since when: the macro was added in #5151 (58cfecf, 2026-05-19) and is not part of a release yet.
Possible fix: build the message with detail::concat (which appends any type with data()/size()) and a dump() that cannot throw on invalid UTF-8. I tested this with the program below (C++11 and C++17) and with the alt_json type from tests/src/unit-alt-string.cpp; the messages checked in tests/src/unit-conversions.cpp are unchanged for valid strings, but I did not run the test suite:
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE": ", j.dump(-1, '', false, nlohmann::detail::error_handler_t::replace)), &j));
With it, the second case prints [json.exception.out_of_range.410] enum value out of range for Color: "<U+FFFD>", where <U+FFFD> stands for the replacement character written as raw UTF-8.
Reproduction steps
Save the program below as c08.cpp.
Compile it against develop: clang++ -std=c++17 -g -O1 -fsanitize=address,undefined -fno-sanitize-recover=undefined -I include c08.cpp -o c08
Run ./c08.
Expected vs. actual results
Expected: both conversions throw out_of_range.410; with a custom string_t the macro compiles.
Actual: the second conversion throws type_error.316; with a custom string_t (for example the test suite's alt_string) the from_json does not compile.
Minimal code example
#include<nlohmann/json.hpp>
#include<iostream>using json = nlohmann::json;
enumclassColor { red, green };
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(Color,
{
{Color::red, "red"},
{Color::green, "green"},
})
intmain()
{
// unknown value: out_of_range.410 as documentedtry
{
json("blue").get<Color>();
}
catch (const json::exception& e)
{
std::cout << e.what() << '\n';
}
// unknown value that is a string with invalid UTF-8 (e.g., from from_cbor(), see #5529)// expected: out_of_range.410// actual: type_error.316, thrown by the j.dump() that builds the messagetry
{
json("\xFF").get<Color>();
}
catch (const json::exception& e)
{
std::cout << e.what() << '\n';
}
}
Error messages
[json.exception.out_of_range.410] enum value out of range for Color: "blue"
[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF
Compiler and operating system
Apple clang 21.0.0 (clang-2100.3.34.2), macOS 27.0 (arm64); the custom string_t compile error also with GCC 16.2 (/opt/homebrew/bin/g++-16)
Description
The
from_jsongenerated byNLOHMANN_JSON_SERIALIZE_ENUM_STRICTbuilds its error message with"..." + j.dump(). This has two consequences:j.dump()throwstype_error.316while the message is being built, so the caller getstype_error.316instead of the documentedout_of_range.410. Such strings reachget<Enum>()for example fromfrom_cbor()/from_msgpack(), which do not validate UTF-8 (from_cbor()/from_msgpack() do not validate UTF-8 in text strings at decode time (only dump() does) #5529), or from strings assigned by the program.string_t,j.dump()returnsstring_t, andconst char* + string_tdoes not compile unless the type happens to provide thatoperator+(not among the documentedStringTyperequirements), and the result must also convert to theconst std::string&thatout_of_range::createtakes. For example,get<Color>()with thealt_jsontype fromtests/src/unit-alt-string.cppfails witherror: invalid operands to binary expression ('const char[36]' and 'string_t' (aka 'alt_string'))atmacro_scope.hpp:339.The code is at
include/nlohmann/detail/macro_scope.hpp#L339:The
NLOHMANN_JSON_SERIALIZE_ENUM_STRICTdocumentation says: "Undefined input throwsout_of_range.410in both directions".Since when: the macro was added in #5151 (58cfecf, 2026-05-19) and is not part of a release yet.
Possible fix: build the message with
detail::concat(which appends any type withdata()/size()) and adump()that cannot throw on invalid UTF-8. I tested this with the program below (C++11 and C++17) and with thealt_jsontype fromtests/src/unit-alt-string.cpp; the messages checked intests/src/unit-conversions.cppare unchanged for valid strings, but I did not run the test suite:With it, the second case prints
[json.exception.out_of_range.410] enum value out of range for Color: "<U+FFFD>", where<U+FFFD>stands for the replacement character written as raw UTF-8.Reproduction steps
c08.cpp.develop:clang++ -std=c++17 -g -O1 -fsanitize=address,undefined -fno-sanitize-recover=undefined -I include c08.cpp -o c08./c08.Expected vs. actual results
out_of_range.410; with a customstring_tthe macro compiles.type_error.316; with a customstring_t(for example the test suite'salt_string) thefrom_jsondoes not compile.Minimal code example
Error messages
Compiler and operating system
Apple clang 21.0.0 (clang-2100.3.34.2), macOS 27.0 (arm64); the custom
string_tcompile error also with GCC 16.2 (/opt/homebrew/bin/g++-16)Library version
develop@ 633de8eValidation
developbranch is used.This issue was written by Claude Code on behalf of @nlohmann.