json: Add Key name to Exception

Bug Report

(I’m interested in developing this feature, so pointers are appreciated)

  • When working with an invalid json, the exception produced is not really helpfull.

I’v found out https://github.com/nlohmann/json/issues/160 - but that’s a different issue than the one I’m having, and it will also be harder to fix because the values have no notion of key, the specific code I’m talking about on json.hpp follows this pattern:

template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
    if (JSON_UNLIKELY(not j.is_string()))
    {
        JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
    }
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}

but even if we have a small json to handle, the output is not really helpfull:

std::exception: [json.exception.type_error.302] type must be string, but is number

  • Small code example:
nlohmann::json j {{"firstElement", ""}};
j["firstElement"] = 0;

  • What is the expected behavior? std::exception: [json.exception.type_error.302] type for key firstElement must be string, but is number

  • Did you use a released version of the library or the version from the develop branch?

3.0.1

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 40 (21 by maintainers)

Most upvoted comments

Maybe a compromise between keeping the size down and the ability to report the stack is that if NDEBUG is not defined, then basic_json<> contains a basic_json<> *parent; that is set when an array or object adds the object to its collection. That’s the minimum size that would allow you to walk back up the chain. The function that throws the exception can then walk the parent chain to rebuild the JSON value path.

FWIW, I ended up writing a template helper function to wrap the exception. I still think it should be included by default, but at least this works:

// get - json helper; gets value of key or throws
template<class T>
T get(const json& j, string key) {
    auto it = j.find(key);
    if(it == j.end())
        throw runtime_error("get(json) - key not found - "+key);

    try {
        return it->get<T>();
    } catch(const exception& e) {
        throw runtime_error("get(json) - get-exception - "+key+" - "+e.what());
    }
}

a try that I know it’s wrong for the library as I used a external variable, but if you feel that this could be somewhat userfull I’ll rework to merge on the json lib.

external std::string last_used_key;

on the operator[] for the objects:

    const_reference operator[](const typename object_t::key_type& key) const
    {
				last_used_key = key;
                               ....
    }

on the exception:

protected:
    exception(int id_, const char* what_arg)
		: id(id_), what_error(std::string(what_arg) + " Possible Key: " + last_used_key), m(what_error.c_str())
		 {
		 }

This adds for me what I wanted, overhead is negligible wiht my tests and the result of the exception is better:

[json.exception.type_error.302] type must be string, but is number. Possible Key: cardType

[json.exception.type_error.302] type must be number, but is string this thing makes me crazy when you work with external server that could send any response