std::optional<T> direct construction from JSON null throws instead of yielding std::nullopt
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 50.6k
- Forks
- 7.5k
- Avg merge
- 4d 17h
- Merged PRs (30d)
- 58
Description
Description
Constructing or assigning std::optional<T> directly from a JSON null value throws type_error instead of yielding std::nullopt. Only the explicit .get<std::optional<T>>() form works correctly.
Reproduction
#include <nlohmann/json.hpp>
#include <optional>
int main() {
nlohmann::json j_null;
// Works correctly
auto opt1 = j_null.get<std::optional<std::string>>(); // → std::nullopt ✓
// Throws type_error 302
std::optional<std::string> opt2 = j_null; // ✗ throws
std::optional<std::string> opt3(j_null); // ✗ throws (direct-init also fails)
}
Error: [json.exception.type_error.302] type must be string, but is null
Expected behavior
Direct construction/assignment should yield std::nullopt, consistent with .get<std::optional<T>>().
Environment
- Compiler: GCC 16.1.0, Apple Clang 21.0.0
- C++ standard: C++17 and later
- Library version:
developbranch
Why this cannot be cleanly fixed
This is a limitation at the C++ language level, not a library bug:
std::optional<T>has its own converting constructor that accepts any type constructible fromTT(e.g.,std::string) is constructible frombasic_jsonviabasic_json::operator T()- When both constructors are viable, std::optional's own constructor wins overload resolution
- There is no SFINAE trick to distinguish "being called from inside std::optional's own constructor" from a direct call
A proper fix would require restricting or redesigning basic_json::operator ValueType() (json.hpp:1946-1971), which is relied upon for all ordinary implicit conversions (e.g., std::string s = json_obj;). Such a change would be a breaking change to the core conversion API and belongs in a major-version redesign.
Workaround
Use .get<std::optional<T>>() or .get_to() for std::optional<T> conversions:
auto opt = j_null.get<std::optional<std::string>>(); // → std::nullopt ✓
j_null.get_to(opt); // → std::nullopt ✓
Related
- #4864: Original
std::optionalsupport issue (now fixed ondevelop) - #3453: Type-strictness redesign for 4.0 (where a permanent fix could live)
Note: This issue was filed by Claude Code to track a limitation separate from #4864.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the conversion operator in json.hpp:1946-1971 and compare direct std::optional construction with the documented .get<std::optional>() and get_to() workarounds. Review related issues #4864 and #3453 to determine whether this limitation belongs in a future type-strictness redesign; done means establishing whether a non-breaking fix is possible or documenting the limitation and workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100