Repository navigation
msgpack parser failed to parse null as Map key #3381
Description
Activity
This is indeed not supported by the library as JSON requires object keys to be strings. I am hesitant to implement a workaround like treating
nullas a string.In any case, we should overwork the documentation to be explicit about the restrictions.
Reacted by 双草酸酯- addedaspect: binary formatsBSON, CBOR, MessagePack, UBJSONBSON, CBOR, MessagePack, UBJSONstate: please discussplease discuss the issue or vote for your favorite optionplease discuss the issue or vote for your favorite option
on Mar 8, 2022 In Python APIs there is a param
bool strict_map_key=True, which does the thing.falbrechtskirchinger commented
on Mar 9, 2022 ContributorMore actionsThis is indeed not supported by the library as JSON requires object keys to be strings. I am hesitant to implement a workaround like treating
nullas a string.This would only need to apply to the parser, though? The user can be responsible for translating lookups to
j["null"]where necessary.Can it be at least enabled on the sax parser? (all integer, unsigned integer, float ecc )
The virtual function (example
json_sax::key(json_sax::number_integer_t)) can be defaulted to fail parsing while leaving the possibility to the user implementation of the parser to override itIs this possible?
Thanks,
Lucafalbrechtskirchinger commented
on Apr 12, 2022 ContributorMore actionsNo. The parser expects a string for keys. This happens before the SAX interface is involved.
bool get_msgpack_object(const std::size_t len) { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } string_t key; for (std::size_t i = 0; i < len; ++i) { get(); if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) // <-- string key is parsed/required here { return false; }
Sorry but the parse except a string because it is the only thing that know how to parse, can something like this be implemented?
bool get_msgpack_object(const std::size_t len) { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } for (std::size_t i = 0; i < len; ++i) { switch (get()) { // EOF case std::char_traits<char_type>::eof(): return false; // Or whatever // positive fixint case 0x00: // Various bytes omitted... case 0x7F: if( ! sax->key_number_integer(static_cast<number_unsigned_t>(current) ) ) return false; break; // fixstr case 0xA0: // Various bytes omitted... case 0xDB: // str 32 { // NORMAL STRING CASE string_t s; if( ! ( get_msgpack_string(s) && sax->key(s) ) ) return false; break; } case 0xC0: // nil if( ! sax->key_null() ) return false; break; case 0xC2: // false if( ! sax->key_bool(false) ) return false; break; case 0xC3: // true if( ! sax->key_bool(true) ) return false; break; // And so on with other meaningful types } if(JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())){ return false; } }
falbrechtskirchinger commented
on Apr 12, 2022 ContributorMore actionsWhat you did is a start but more special-casing in other places is required to keep things from breaking.
For starters, the main parser is implemented on top of the SAX interface and can't support this extended key API because, as you know, the object container's key type is always
basic_json::string_t. There's probably more.In any case, this library is a conforming implementation of the msgpack specification according to OP's quotes. So, is it worth the effort? I don't know.
@nlohmann will have to weigh in if a PR to add arbitrary key types to the SAX interface would be accepted. I'm just another user and have no strong feelings either way.
Yeah I know the the default object container's key type is always
basic_json::string_tand I don't want to change that, the defaultjson_saxparser on its supposed virtual functionjson_sax::key_number_integer(json_sax::number_integer_t)should simplyreturn false, this will keep same behaviour as present (fail to parse) but also let the user extend funtionalityWith an extension like this @kotori2 could simply extend the sax parser with:
bool json_sax::key_null() override { return this->key("null"); }Giving him his excepted result:
{ "null": 1 }given the input:
{ null: 1 }while at the same time keeping the current interface and behaviour
Reacted by 双草酸酯 and DeepBlueV7.Xfalbrechtskirchinger commented
on Apr 12, 2022 ContributorMore actionsSounds good. Are you interested in pursing this in form of a PR?
Reacted by Luca PassarellaThanks for the report, and sorry for the long silence. We decided not to support non-string map keys. JSON object keys are always strings, and the MessagePack spec explicitly allows implementations to restrict keys to strings for JSON compatibility. Turning keys into strings (e.g.
nil→"null") would lose information and can create duplicate keys ({1: a, "1": b}). Typed keys in the SAX interface would need a larger API change than the demand justifies.#5594 makes the error say what went wrong ("only string keys are supported, but found nil") and documents the restriction. For data with non-string keys, please use a general-purpose MessagePack library. Closing as won't fix.
(This comment was written by Claude Code.)
- added a commit that references this issue
on Sep 28, 2026
What is the issue you have?
I'm trying to parse msgpack data like:
which serializes as
81 C0 01. Butnlohmann::json::from_msgpackfailed to parse it withPlease describe the steps to reproduce the issue.
↓
Can you provide a small but working code example?
What is the expected behavior?
From the msgpack specs it doesn't restricts which value could be used on Map keys
And what is the actual behavior instead?
The specs above says
So maybe it could be serialized to
like other implementation does
Which compiler and operating system are you using?
Also reproduced on gcc11
Which version of the library did you use?
developbranchIf you experience a compilation error: can you compile and run the unit tests?