# Frequently Asked Questions (FAQ) ## Known bugs ### Brace initialization yields arrays Question Why does ``` json j{true}; ``` and ``` json j(true); ``` yield different results (`[true]` vs. `true`)? This is a known issue, and -- even worse -- the behavior differs between GCC and Clang. The "culprit" for this is the library's constructor overloads for initializer lists to allow syntax like ``` json array = {1, 2, 3, 4}; ``` for arrays and ``` json object = {{"one", 1}, {"two", 2}}; ``` for objects. Tip To avoid any confusion and ensure portable code, **do not** use brace initialization with the types `basic_json`, `json`, or `ordered_json` unless you want to create an object or array as shown in the examples above. To explicitly create a single-element array, use `json::array({value})`: ``` json j = json::array({true}); // [true] ``` **Opt-in copy semantics (since version 3.13.0 unreleased)** If you define [`JSON_BRACE_INIT_COPY_SEMANTICS`](https://json.nlohmann.me/api/macros/json_brace_init_copy_semantics/index.md) to `1` before including the library, single-element brace initialization is treated as copy/move instead of creating a single-element array: ``` #define JSON_BRACE_INIT_COPY_SEMANTICS 1 #include json obj = {{"key", "value"}}; json j{obj}; // -> {"key":"value"} (copy, not array) ``` Without the macro (default behavior), `json j{obj}` creates `[{"key":"value"}]`. This opt-in macro fixes issue #5074 while preserving backwards compatibility for existing code. ## Limitations ### Relaxed parsing Question Can you add an option to ignore trailing commas? This library does not support any feature that would jeopardize interoperability. ### Parse errors reading non-ASCII characters Questions - Why is the parser complaining about a Chinese character? - Does the library support Unicode? - I get an exception `[json.exception.parse_error.101] parse error at line 1, column 53: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '"Testé$')"` The library supports **Unicode input** as follows: - Only **UTF-8** encoded input is supported, which is the default encoding for JSON, according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1). - `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers. - Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors. - The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1). - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. - When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/index.md) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding. ### NUL bytes in the input Questions - Why does [`json::parse()`](https://json.nlohmann.me/api/basic_json/parse/index.md) silently ignore part of my input? - Why does a `std::string`/buffer with extra data after the JSON text parse without error, while a similar-looking string with extra text does not? A `'\0'` (NUL) byte anywhere in the input is treated the same as the real end of the input, rather than as an ordinary (and, outside of a string, invalid) byte. Everything from that byte onward is silently ignored, without a parse error — including further, otherwise well-formed JSON: ``` json::parse(std::string("123") + '\0'); // == 123, no error json::parse(std::string("123") + '\0' + "true"); // == 123, the "true" is silently ignored too ``` This is different from any other unexpected trailing byte, which *does* raise [`parse_error.101`](https://json.nlohmann.me/home/exceptions/#jsonexceptionparse_error101): ``` json::parse("123x"); // throws parse_error.101: unexpected additional data ``` This falls out of the same convention used when no explicit input length is given at all: `json::parse(const char*)` already stops at the first NUL byte via `strlen()`, since a bare pointer has no length of its own. The library applies that same NUL-terminated-C-string convention uniformly, rather than only when a length is genuinely unavailable — so a `std::string`, iterator range, or container whose content happens to include a NUL byte is affected the same way a raw `const char*` would be. If your input may contain a trailing or embedded NUL that is **not** meant to signal the end of the JSON text — for instance, a fixed-size, zero-padded buffer — trim it yourself before calling `parse()`, since the library will otherwise silently stop there instead of raising an error: ``` s.resize(s.find('\0')); // drop everything from the first NUL onward, if any json::parse(s); ``` **Opt-in strict handling (since version 3.13.0 unreleased)** Manually trimming every input is easy to forget. If you define [`JSON_STRICT_NUL_HANDLING`](https://json.nlohmann.me/api/macros/json_strict_nul_handling/index.md) to `1` before including the library, a `'\0'` byte is instead rejected like any other unexpected byte and raises `parse_error.101`, instead of being treated as end of input: ``` #define JSON_STRICT_NUL_HANDLING 1 #include json::parse(std::string("123") + '\0'); // throws parse_error.101 instead of silently returning 123 ``` This macro defaults to `0` (disabled, preserving the behavior described above) to avoid breaking existing code that may depend on it, even unknowingly; it is planned to become the default in version 4.0.0. See [its documentation](https://json.nlohmann.me/api/macros/json_strict_nul_handling/index.md) for details, including how it also affects `char` arrays such as string literals. Note that this is unrelated to an *unescaped* NUL byte occurring **inside** a quoted JSON string, which is a different, already-invalid case and is correctly rejected either way: ``` json::parse(std::string("\"") + '\0' + "\""); // throws parse_error.101: control character U+0000 (NUL) must be escaped to \u0000 ``` ### Wide string handling Question Why are wide strings (e.g., `std::wstring`) dumped as arrays of numbers? As described [above](#parse-errors-reading-non-ascii-characters), the library assumes UTF-8 as encoding. To store a wide string, you need to change the encoding. Example ``` #include // codecvt_utf8 #include // wstring_convert // encoding function std::string to_utf8(std::wstring& wide_string) { static std::wstring_convert> utf8_conv; return utf8_conv.to_bytes(wide_string); } json j; std::wstring ws = L"車B1234 こんにちは"; j["original"] = ws; j["encoded"] = to_utf8(ws); std::cout << j << std::endl; ``` The result is: ``` { "encoded": "車B1234 こんにちは", "original": [36554, 66, 49, 50, 51, 52, 32, 12371, 12435, 12395, 12385, 12399] } ``` ## Usage ### Thread safety Question Is `basic_json` thread-safe? No. `basic_json` provides no built-in synchronization, the same as `std::map` or `std::vector`. Concurrent reads of the same value from multiple threads are safe, as are concurrent (non-overlapping) accesses to independent `json` objects. However, any concurrent write to a `json` object -- or a concurrent read while another thread writes to the same object -- is a data race and requires external synchronization (e.g., a `std::mutex`) by the caller. ### Schema validation Question Does this library support JSON Schema validation? Not directly, but the companion project [json-schema-validator](https://github.com/pboettch/json-schema-validator) builds JSON Schema (draft 7; draft 4 in its older, now-superseded 1.x releases) validation on top of this library and is a common recommendation for this use case. ## Exceptions ### Parsing without exceptions Question Is it possible to indicate a parse error without throwing an exception? Yes, see [Parsing and exceptions](https://json.nlohmann.me/features/parsing/parse_exceptions/index.md). ### Key name in exceptions Question Can I get the key of the object item that caused an exception? Yes, you can. Please define the symbol [`JSON_DIAGNOSTICS`](https://json.nlohmann.me/api/macros/json_diagnostics/index.md) to get [extended diagnostics messages](https://json.nlohmann.me/home/exceptions/#extended-diagnostic-messages). ## Serialization issues ### Number precision Question - It seems that precision is lost when serializing a double. - Can I change the precision for floating-point serialization? The library uses `std::numeric_limits::digits10` (15 for IEEE `double`s) digits for serialization. This value is sufficient to guarantee roundtripping. If one uses more than this number of digits of precision, then string -> value -> string is not guaranteed to round-trip. [cppreference.com](https://en.cppreference.com/w/cpp/types/numeric_limits/digits10) The value of `std::numeric_limits::digits10` is the number of base-10 digits that can be represented by the type T without change, that is, any number with this many significant decimal digits can be converted to a value of type T and back to decimal form, without change due to rounding or overflow. Tip The website gives a good insight into the internal storage of floating-point numbers. See [this section](https://json.nlohmann.me/features/types/number_handling/#number-serialization) on the library's number handling for more information. ### Serializing untrusted or invalid UTF-8 Questions - Why does `dump()` throw when I serialize data that came from the network? - Is CVE-2024-34363 a vulnerability in this library? Crashes reported against this library that stem from an uncaught [`type_error.316`](https://json.nlohmann.me/home/exceptions/#jsonexceptiontype_error316) while serializing unvalidated input (e.g., CVE-2024-34363) are a usage issue, not a library vulnerability: [`dump()`](https://json.nlohmann.me/api/basic_json/dump/index.md) throws in its default `strict` mode because [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-8.1) requires JSON text to be valid UTF-8. The recommended pattern is to pass a non-strict [`error_handler`](https://json.nlohmann.me/api/basic_json/error_handler_t/index.md) or to handle the exception: ``` // replace invalid sequences with U+FFFD instead of throwing const auto s = j.dump(-1, ' ', false, json::error_handler_t::replace); ``` ### Using JSON values with `std::format` or `fmt` Question - Can I use `std::format("{}", j)` on a JSON value? - Can I use `fmt::format("{}", j)` or `fmt::print("{}", j)` (the [{fmt}](https://github.com/fmtlib/fmt) library) on a JSON value? `std::format` works out of the box since version 3.13.0 unreleased, as long as the standard library provides `` (see [`JSON_HAS_STD_FORMAT`](https://json.nlohmann.me/api/macros/json_has_std_format/index.md)); see [`std::formatter`](https://json.nlohmann.me/api/basic_json/std_formatter/index.md) for details, including the `"{:#}"` pretty-print spec, indent widths (`"{:2}"`), and custom indent characters (`"{:.>#}"`). For `fmt`, the library ships [`format_as`](https://json.nlohmann.me/api/basic_json/format_as/index.md), a small customization point `fmt` looks for via argument-dependent lookup. It only has an effect on fmt 10.0.0 through 11.0.2 — from fmt 11.1.0 onwards, `fmt` no longer picks up a `format_as` overload that returns a `std::string`. On such versions (or any version, if you also want the same `"{:#}"`/width/fill-and-align spec support that `std::formatter` has), define your own `fmt::formatter` specialization; see [`format_as`](https://json.nlohmann.me/api/basic_json/format_as/index.md) for a recipe that mirrors it. If you get ambiguous-overload errors when passing a JSON value to `fmt::format`/`fmt::print` without any `fmt::formatter` specialization in scope, that's `fmt` picking up `basic_json`'s implicit `operator ValueType()` conversion operator (see [#964](https://github.com/nlohmann/json/issues/964) and [#958](https://github.com/nlohmann/json/issues/958)); disabling it via [`JSON_USE_IMPLICIT_CONVERSIONS 0`](https://json.nlohmann.me/api/macros/json_use_implicit_conversions/index.md) avoids the ambiguity. ## Compilation issues ### Android SDK Question Why does the code not compile with Android SDK? Since [NDK r18](https://github.com/android/ndk/wiki/Changelog-r18) (2018), GCC and the `gnustl`/`stlport` C++ libraries have been removed from the Android NDK; Clang and `libc++` are now the only compiler and C++ library, and they support C++11 and later out of the box. With a current NDK, no special configuration is needed to use this library. Only very old NDKs (before r18), which defaulted to GCC and `gnustl`, lacked C++11 library features such as `std::to_string`. If you run into this, update to a current NDK. ### Missing STL function Questions - Why do I get a compilation error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`)? - Why does the code not compile with MinGW or Android SDK? This is not an issue with the code, but rather with the compiler itself. On Android, use a current NDK (see above). For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug.