This error tells you that ArduinoJson cannot return the type you requested. The message incorrectly mentions the type String, but you can find the actual name with the alias T on the line before.

  1. If T is char, you must replace it with int8_t, uint8_t, or any other integral type.
  2. If T is char*, you must replace it with const char*.
  3. If T is neither char nor char*, continue reading.

Support for char and char* was deprecated in 6.18 and removed in 6.20

How do we get this error?

As an example, we’ll take the tm structure, which describes an instant in time. This structure is declared in the standard C header <time.h>.

You could be tempted to extract a tm instance from a JsonDocument like so:

tm timestamp = doc["timestamp"];

However, if you do that, you’ll receive the following compilation error:

In file included from [...]/ArduinoJson.hpp:37:0,
                 from [...]/ArduinoJson.h:9,
                 from MyProject.ino:9:
[...]/ArduinoJson/Variant/ConverterImpl.hpp: In instantiation of 'static T Converter<T, Enable>::fromJson(JsonVariantConst) [with T = tm; Enable = void]':
[...]/ArduinoJson/Variant/JsonVariant.hpp:107:34:   required from 'typename enable_if<((! is_same<T, char*>::value) && (! is_same<T, char>::value)), T>::type JsonVariant::as() const [with T = tm; typename enable_if<((! is_same<T, char*>::value) && (! is_same<T, char>::value)), T>::type = tm]'
[...]/ArduinoJson/Variant/JsonVariant.hpp:150:17:   required from 'JsonVariant::operator T() const [with T = tm]'
[...]/ArduinoJson/Object/MemberProxy.hpp:85:30:   required from 'MemberProxy<TParent, TStringRef>::operator T() const [with T = tm; TObject = JsonDocument&; TStringRef = const char*]'
MyProject.ino:15:33:   required from here
[...]/ArduinoJson/Variant/ConverterImpl.hpp:24:20: error: invalid initialization of reference of type 'String&' from expression of type 'tm'
     convertFromJson(src, result);  // Error here? See
[...]/ArduinoJson/Variant/ConverterImpl.hpp:262:13: note: in passing argument 2 of 'void convertFromJson(JsonVariantConst, String&)'
 inline void convertFromJson(JsonVariantConst src, ::String& dst) {

Keep on reading if you see no matching function for call to 'convertFromJson(...) in your output. There are different errors depending on the target type, but the interpretation is the same.

The compiler tried to call a function named convertFromJson(src, result), where src has the type JsonVariantConst, and result has the type tm. It attempted to solve this function call by creating a temporary String, but it failed.

convertFromJson() is a function of ArduinoJson that converts a JSON value (the JsonVariantConst) to another type (tm, in this case). Here, the call fails because no overload of convertFromJson() supports the tm type. In other words, ArduinoJson doesn’t know how to extract a tm value from a JsonDocument.

How to fix this error?

I’ll show how to fix the error for tm, but you can apply the same resolution for any default-constructible type (see next section for non-default-constructible types).

As we just saw, this error is due to the fact that ArduinoJson doesn’t know how to extract a tm from a JsonDocument, so you need to tell him how to do that.

You must create an overload of convertFromJson() that supports tm. For example, you could write:

void convertFromJson(JsonVariantConst src, tm& dst) {
  strptime(<const char*>(), "%FT%TZ", &dst);

You must declare this function in the same namespace as the type you want to convert (the global namespace in the case of tm) so that the compiler can find it through ADL.

How to support non-default-constructible types?

Before calling convertFromJson(), ArduinoJson creates an instance of the target type to pass a reference as a second argument. This requires that the type is default-constructible; otherwise, ArduinoJson wouldn’t know how to construct the instance.

Therefore, you cannot use convertFromJson() for non-default-constructible types. Instead, you must use a lower-level hook based on the specialization of Converter<T>, like so:

template <>
struct Converter<tm> {
  static tm fromJson(JsonVariantConst src) {
    tm result;
    strptime(<const char*>(), "%FT%TZ", &dst);
    return result;

Of course, tm is default-constructible, but you get the idea, right?

See also