# 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 <nlohmann/json.hpp>

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 <nlohmann/json.hpp>

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> // codecvt_utf8
#include <locale>  // wstring_convert

// encoding function
std::string to_utf8(std::wstring& wide_string)
{
    static std::wstring_convert<std::codecvt_utf8<wchar_t>> 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<number_float_t>::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<T>::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 <https://float.exposed> 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 `<format>` (see [`JSON_HAS_STD_FORMAT`](https://json.nlohmann.me/api/macros/json_has_std_format/index.md)); see [`std::formatter<basic_json>`](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<basic_json>` 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<json>` 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.
