Files
json/docs/mkdocs/docs/api/macros/json_strict_binary_utf8.md
Niels Lohmann d8d47be4a5 Fix CI on develop after merging the ready-to-merge PRs (#5754)
* Keep the serializer conversion for objects whose keys cannot be converted

#5591 added a test converting nlohmann::json into a basic_json whose
string type cannot be constructed from std::string. That instantiates
convert_iteratively(), whose members.emplace_back(next.key(), ...) needs
exactly that key conversion, and broke the build of unit-alt-string.
Dispatch on the key's constructibility and leave such conversions to the
serializers, as the levels above the nesting bound already do (#3425).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix the remaining CI failures on develop

- unit-wstring: with a 16-bit wchar_t (Windows), a lone surrogate is
  reported as the ill-formed byte 0xFF since #5704; the std::wstring
  expectations still had the previous <U+0000>.
- ci_single_binaries: json_literals.hpp (#5610) and json.hpp include each
  other on purpose, and IWYU, not following the cycle, asks to replace
  json.hpp with json_fwd.hpp. Report its findings without failing the
  build, as already done for json.hpp.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix the library warnings and noexcept specifications from the merged PRs

- binary_reader: rename the error_handler constructor parameter, which
  shadowed the member (-Wshadow, -Wshadow-field-in-constructor; #5746)
- basic_json(copy_construct_tag, ...): declare it noexcept when copying
  the base class is (GCC 16 -Wnoexcept; #5690)
- the scalar-on-left legacy comparison operators: noexcept only when
  converting the scalar is, like their member counterparts (#5682, #5751)
- compare_leaves: use std::is_eq/is_lt/is_gt instead of comparing a
  std::partial_ordering with 0 (-Wzero-as-null-pointer-constant; #5686)
- serializer: silence MSVC C4127 for the EnsureAscii template parameter
  (#5741, #5746)
- clang-tidy: return the sanitized reference in binary_writer, take the
  key of ordered_map::find_impl by const reference (#5727), and mark the
  switches over parse_array_index (#5728)
- ordered_map: keep <memory> for std::allocator (IWYU)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Split unit-conversions.cpp so MinGW can link it

clang 18 with the MinGW linker failed to link test-conversions_cpp17
("relocation truncated to fit: IMAGE_REL_AMD64_REL32"). As windows.yml
recommends, keep the objects small by splitting the test file.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix the tests added by the merged PRs for all CI configurations

- discard the results of dump() and from_*() in CHECK_THROWS with
  utils::ignore_return_value (GCC -Werror=unused-result)
- give unit-bson's huge_string_t a default constructor (MSVC C2512,
  GCC 5, clang 3.5)
- unit-disabled_exceptions: use the literals namespace when the global
  UDLs are off (ci_test_noglobaludls; #5700)
- unit-binary_utf8_strict: expect the JSON pointer prefix with
  JSON_DIAGNOSTICS (#5741)
- skip the tests that rely on exceptions under JSON_NOEXCEPTION
  (#5678, #5732)
- clang-tidy and clang -Werror: static test data, CAPTURE(...);,
  const-correctness, use-after-move alias, unused conversion operator,
  a missing <iterator> include

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Title the macro examples and add JSON_STRICT_BINARY_UTF8 to the docset

The documentation style check requires "Example: ..." titles on pages with several examples (#5741, #5591) and a docset entry for every macro page.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Regenerate BUILD.bazel and nlohmann_json.natvis

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

#5746 added detail/output/error_handler.hpp and #5741 the json_abi_sbu8 ABI tag.

* Install libidn11 for the CMake 3.5.0 binary in ci_cmake_flags

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

#5733 moved ci_cmake_options from ubuntu:focal to ubuntu:24.04, which no longer ships libidn.so.11; the CMake 3.5.0 release binary links against it, so every ci_cmake_flags run has failed since. Install focal's libidn11 package for that matrix entry only.

* Suppress Infer's false STACK_VARIABLE_ADDRESS_ESCAPE in get_impl

get_impl() returns its local by value. A test added by the merged PRs instantiates it with a type Infer misreads, so ci_infer reported the 2021 code for the first time.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-04 17:18:19 +02:00

4.0 KiB

JSON_STRICT_BINARY_UTF8

#define JSON_STRICT_BINARY_UTF8 /* value */

When defined to 1, the error_handler parameter of the binary writers to_cbor, to_ubjson, to_bjdata, and to_bson defaults to error_handler_t::strict instead of error_handler_t::keep. These writers then check every string value and object key for valid UTF-8 and throw type_error.316 for ill-formed UTF-8, like dump does. Without it, they write the bytes unchanged. An error_handler passed explicitly always takes precedence.

The macro does not affect:

  • to_msgpack: the MessagePack specification allows a str value to contain bytes that are not valid UTF-8, so its error_handler always defaults to keep.
  • to_bon8: BON8 always checks, because the UTF-8 lead bytes mark where a string ends.
  • The binary readers (from_cbor, from_msgpack, from_ubjson, from_bjdata, from_bson): none of these formats requires a decoder to reject ill-formed UTF-8, so they always return the bytes unchanged.

Default definition

The default value is 0 (disabled, the behavior of version 3.12.0 and earlier is preserved).

#define JSON_STRICT_BINARY_UTF8 0

Notes

!!! note "Background"

CBOR, UBJSON, BJData, and BSON all require strings to be UTF-8. Up to version 3.12.0, the writers did not check
this, so they could produce output that other decoders reject. Checking by default would break code that stores
other encodings (for instance ISO 8859-1) in a string and only ever writes it to a binary format. You can pass
`error_handler_t::strict` to each call, or use this macro to check by default ahead of version 4.0.0, where
`strict` is planned to become the default (see
[#5529](https://github.com/nlohmann/json/issues/5529) and [#5651](https://github.com/nlohmann/json/issues/5651)).

!!! warning "Opt-in only"

This macro must be defined **before** including `<nlohmann/json.hpp>`. Defining it after the include has no
effect.

!!! note "ABI compatibility"

The value of this macro is encoded in the [namespace](../../features/namespace.md) (tag `_sbu8`), resulting in
distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program
without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.

Examples

??? example "Example: default behavior (macro not defined)"

Without the macro, the bytes are written unchanged:

```cpp
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    auto v = json::to_cbor(json("\xFF"));
    // v is {0x61, 0xFF}
}
```

??? example "Example: opt-in check (macro defined to 1)"

With the macro, ill-formed UTF-8 is rejected:

```cpp
#define JSON_STRICT_BINARY_UTF8 1
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    auto v = json::to_cbor(json("\xFF"));
    // throws type_error.316: invalid UTF-8 byte at index 0: 0xFF
}
```

See also

  • to_cbor - create a CBOR serialization of a JSON value
  • to_ubjson - create a UBJSON serialization of a JSON value
  • to_bjdata - create a BJData serialization of a JSON value
  • to_bson - create a BSON serialization of a JSON value
  • error_handler_t - how dump treats ill-formed UTF-8

Version history

  • Added in version 3.13.0.
  • Planned to become the default (with the macro removed) in version 4.0.0.