What’s the problem?

Due to the way JsonVariant and String implement implicit type conversion, you can construct a String from a JsonVariant, but you cannot assign a JsonVariant to an existing String.

For example, in the following snippet, the first line works but the second produces a compilation error:

String name = doc["name"];  // contruction -> works
name = doc["name"];         // assignment  -> fails

If you try to compile this snippet, you get the following error:

error: ambiguous overload for 'operator=' (operand types are 'String' and ...)
   name = doc["name"];
                    ^
note: candidate: String& String::operator=(const String&)
note: candidate: String& String::operator=(const char*)
note: candidate: String& String::operator=(const __FlashStringHelper*)
note: candidate: String& String::operator=(String&&)
note: candidate: String& String::operator=(StringSumHelper&&)

Indeed, since JsonVariant supports implicit conversion to both const char* and String, the compiler doesn’t know which constructor of String should be called, so it deems the operator as “ambiguous”.

How to solve it?

Solution 1: cast

We need to help the compiler pick the right constructor of String. One way is to cast the JsonVariant to const char*, like so:

name = (const char*)doc["name"]; 

Note that we cannot cast to String because it’s equivalent to calling the (ambiguous) constructor.

Solution 2: as<T>()

Another way is to use JsonVariant::as<T>(), which explicitly converts the JsonVariant to the specified type.
For example, any of these lines would work:

name = doc["name"].as<const char*>();
name = doc["name"].as<String>();

Solution 3: no String

Lastly, like most String class issues, the best solution is often to replace it with a const char* or a char[].

Indeed, the problem doesn’t exists with const char*:

const char* name = doc["name"];  // contruction -> works
name = doc["name"];              // assignment  -> works as well

Just remember that the variable name points to the value in the JsonDocument, so it’s not a copy.

Instead, if you need to make a copy you can use a char[] like so:

char name[32];
strlcpy(name, doc["name"] | "", 32);

When you use strcpy() or strlcpy(), always provide a default value ("", here) because passing NULL to these functions leads to undefined behavior.

See also

Global warming stripes by Professor Ed Hawkins (University of Reading)