Search code examples
c++jsonconfignlohmann-json

How to handle nlohmann exception.type_error in a readable way


I'm using nlohmann json to parse a config.json file. The file will be modified by other developers, who use my code.

try {
        conf.x1 = data.at("x1");
        conf.x2 = data.at("x2");
        // ...
        conf.xN = data.at("xN");
} catch (const nlohmann::json::out_of_range &e) {
        std::cerr << "Error. " << e.what() << std::endl;
        return std::nullopt;
} catch (const nlohmann::json::type_error &e) {
        std::cerr << "Error. " << e.what() << std::endl;
        return std::nullopt;
}
  1. When getting the nlohmann::json::out_of_range exception, the e.what() reads: [json.exception.out_of_range.403] key 'x1' not found
  2. When getting the nlohmann::json::type_error exception, it's [json.exception.type_error.302] type must be number, but is string

In the 1st case it easily tells the user that the value x1 is expected, but not found, even though I catch over the whole block. For the 2nd case there are no hints which entry caused the error, forcing the user to search through the whole file.

I thought about writing a function that does the try-catch, e.g. int read_data(const std::string key), but the return values are different, which I guess could be solved with templates or writing a function for each type.

As this complicates the code, I first wanted to find out if there is a simpler alternative, similar to the out_of_range exception.


Solution

  • Found the answer while writing this question:

    In the FAQ it says to define JSON_DIAGNOSITCS. Reading further:

    As this global context comes at the price of storing one additional pointer per JSON value and runtime overhead to maintain the parent relation, extended diagnostics are disabled by default. They can, however, be enabled by defining the preprocessor symbol JSON_DIAGNOSTICS to 1 before including json.hpp.

    Thus, while debugging, add the define before the include. For example, simply #ifdef for a debug flag to decide if we want diagnostics. When using CMake, instead passing -D JSON_DIAGNOSTICS=1 on the command line enables the option project-wide.

    #define JSON_DIAGNOSTICS 1
    #include <nlohmann/json.hpp>