Reason 1: Null pointer dereferencing

Usually, a null pointer dereferencing happens when ArduinoJson returns a null, whereas the program expects a string.

Example with strcpy()

strcpy() (or its safer equivalent strlcpy()) is a function from the C standard library that copies a string from one place to another. Unfortunately, its behavior is undefined when one of the arguments is null.

Here is an example that uses strlcpy() with ArduinoJson:

char name[32];

JsonObject& obj = jsonBuffer.parseObject(input);
strlcpy(name, obj["name"], 32);

This program works fine, except when the value "name" is missing from the object because obj["name"] returns NULL. The same thing happens if parsing fails.

Here is how to fix this program:

char name[32];

JsonObject& obj = jsonBuffer.parseObject(input);
strlcpy(name, obj["name"] | "N/A", 32);

This snippet uses the | syntax introduced in ArduinoJson 5.12. It is equivalent to the following code:

char name[32];

JsonObject& obj = jsonBuffer.parseObject(input);

const char* jsonName = obj["name"];
if (jsonName)
  strlcpy(name, obj["name"], 32);
else
  strcpy(name, "N/A");

Example with strcmp()

strcmp() is a function from the C standard library that compares two strings. Here again, the behavior is undefined if one of the arguments is null.

JsonObject& obj = jsonBuffer.parseObject(input);

if (strcmp(root["state"], "OK") == 0) {
  // ...
}

This program works fine, except when the value "state" is missing from the object, because obj["state"] returns NULL. The same thing happens if parsing fails.

Here is how to fix this program:

JsonObject& obj = jsonBuffer.parseObject(input);

if (root["state"] == "OK") {
  // ...
}

Indeed, the JsonVariant returned by root["state"] has a special implementation of the == operator that knows how to compare string safely.

Reason 2: Stack-overflow

A stack overflow happens when you have too many variables in the “stack” memory.

Before reading further, make sure that your target platform does have enough RAM to store the JsonBuffer and possibly the JSON input too:

Once you’re sure that your device has enough RAM, you should move the JsonBuffer to the heap. Just replace your StaticJsonBuffer with a DynamicJsonBuffer.

If your JSON input is stored in the stack, you should move it to the heap too.

For instance, if you have a program like this:

char content[MAX_CONTENT_SIZE];
StaticJsonBuffer<JSON_BUFFER_SIZE> jsonBuffer;

receive(content);
JsonObject& root = jsonBuffer.parseObject(content);

Serial.println(root["name"].asString());

you should transform it like that:

char* content = malloc(MAX_CONTENT_SIZE);
DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE);

receive(content);
JsonObject& root = jsonBuffer.parseObject(content);

Serial.println(root["name"].asString());

free(content);

Reason 3: Incompatible configurations in compilation units

If your program behaves unpredictably, it may be because a different configuration is used in each .ino or .cpp file.

For example, imagine you have two files my_sketch.ino and my_lib.cpp.

The first file starts with:

// File: my_sketch.ino
#define ARDUINOJSON_USE_LONG_LONG 1
#include <ArduinoJson.h>

whereas the second starts with:

// File: my_lib.ino
#define ARDUINOJSON_USE_LONG_LONG 0
#include <ArduinoJson.h>

In that situation, the two compilation units have different sizes for JsonVariant. Because the linker is not able to detect this problem, it produces an executable with some functions using a big JsonVariant and others using small JsonVariant. The executable may work under some conditions but will crash sooner or later.

To fix this bug, you must use the same configuration in all compilation units. A simple way to do that is to share the configuration in a .h file.

Reason 4: use of PROGMEM string with the wrong type

ArduinoJson supports Flash (or PROGMEM) string, but they must have the type const __FlashStringHelper*. A Flash string that is not properly typed will be treated as RAM string, causing the program to crash.

Here is an example:

const char PROGMEM key[] = "the answer";

root[key] = 42; // <- BOOOOOM!!!!

To use a Flash string with ArduinoJson, you must cast the pointer or use the F() macro:

Solution 1: cast the pointer

You just need to pass the same pointer with a different type, so a cast is enough:

const char PROGMEM key_data[] = "the answer";
auto key = reinterpret_cast<const __FlashStringHelper*>(key_data);

root[key] = 42;

Solution 2: use the macro F()

The first solution is not very pleasant to read, so Arduino ships with a macro that hides the cast:

root[F("the answer")] = 42;

There is one drawback with the F(): it doesn’t perform string interning. That means that every call to the macro creates a new string in the program memory, even if the same string was already present. So, be careful with this macro; otherwise, you’ll end up with multiple copies of the same string, and the program will be bigger than it should.

If you need to use the Flash string in several places, you better define a variable, like so:

auto key = F("the answer");

root[key] = 42;