How do we get this error?

This error occurs when you try to call JsonVariant::is<T>() with a type T that ArduinoJson doesn’t support (neither natively nor through a custom converter).

For example, imagine you have the following structure:

struct Point {
  int x, y;

Suppose your program contains a line like this:

if (doc["point"].is<Point>()) 
  // ...

The compiler will produce an error along those lines:

In file included from [...]/ArduinoJson.hpp:37:0,
                 from [...]/ArduinoJson.h:9,
                 from MyProject.ino:9:
[...]/ArduinoJson/Variant/ConverterImpl.hpp: In instantiation of 'static bool Converter<T, Enable>::checkJson(JsonVariantConst) [with T = Point; Enable = void]':
[...]/ArduinoJson/Variant/VariantRefBase.hpp:126:35:   required from 'typename enable_if<(((! ConverterNeedsWriteableRef<T>::value) && (! is_same<T, char*>::value)) && (! is_same<T, char>::value)), bool>::type VariantRefBase<TDerived>::is() const [with T = Point; TDerived = MemberProxy<JsonDocument&, const char*>; typename enable_if<(((! ConverterNeedsWriteableRef<T>::value) && (! is_same<T, char*>::value)) && (! is_same<T, char>::value)), bool>::type = bool]'
MyProject.ino:25:25:   required from here
[...]/ArduinoJson/Variant/ConverterImpl.hpp:32:30: error: invalid initialization of reference of type 'const String&' from expression of type 'Point'
     return canConvertFromJson(src, dummy);  // Error here? See
[...]/ArduinoJson/Variant/ConverterImpl.hpp:272:13: note: in passing argument 2 of 'bool canConvertFromJson(JsonVariantConst, const String&)'
 inline bool canConvertFromJson(JsonVariantConst src, const ::String&) {

How to fix this error?

To allow JsonVariant::is<T>() to work with a custom T, you must define a function canConvertFromJson() like so:

bool canConvertFromJson(JsonVarianConst src, const Point&) {
  return src["x"].is<int>() && src["y"].is<int>();

The second parameter of canConvertFromJson() is required to trigger ADL but must not be used by the function.

How to support non-default-constructible types?

Before calling canConvertFromJson(), 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 canConvertFromJson() 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<Point> {
  static Point checkJson(VariantConstRef src) {
    return src["x"].is<int>() && src["y"].is<int>();

  // (you'll most likely defined fromJson() too)

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

See also